commonmarker 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of commonmarker might be problematic. Click here for more details.

Files changed (501) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -2
  3. data/README.md +67 -42
  4. data/Rakefile +22 -2
  5. data/commonmarker.gemspec +13 -9
  6. data/ext/commonmarker/cmark/api_test/main.c +35 -0
  7. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeError.log +12 -12
  8. data/ext/commonmarker/cmark/build/CMakeFiles/CMakeOutput.log +141 -141
  9. data/ext/commonmarker/cmark/build/api_test/CMakeFiles/api_test.dir/main.c.o +0 -0
  10. data/ext/commonmarker/cmark/build/api_test/api_test +0 -0
  11. data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/houdini_html_u.c.o +0 -0
  12. data/ext/commonmarker/cmark/build/src/CMakeFiles/cmark.dir/iterator.c.o +0 -0
  13. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/houdini_html_u.c.o +0 -0
  14. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark.dir/iterator.c.o +0 -0
  15. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/houdini_html_u.c.o +0 -0
  16. data/ext/commonmarker/cmark/build/src/CMakeFiles/libcmark_static.dir/iterator.c.o +0 -0
  17. data/ext/commonmarker/cmark/build/src/cmark +0 -0
  18. data/ext/commonmarker/cmark/build/src/libcmark.0.19.0.dylib +0 -0
  19. data/ext/commonmarker/cmark/build/src/libcmark.a +0 -0
  20. data/ext/commonmarker/cmark/build/src/libcmark.dylib +0 -0
  21. data/ext/commonmarker/cmark/src/houdini_html_u.c +26 -13
  22. data/ext/commonmarker/cmark/src/iterator.c +2 -2
  23. data/ext/commonmarker/cmark/test/__pycache__/cmark.cpython-34.pyc +0 -0
  24. data/ext/commonmarker/cmark/test/__pycache__/normalize.cpython-34.pyc +0 -0
  25. data/ext/commonmarker/cmark/test/cmark.pyc +0 -0
  26. data/ext/commonmarker/cmark/test/normalize.pyc +0 -0
  27. data/ext/commonmarker/commonmarker.c +276 -3
  28. data/ext/commonmarker/extconf.rb +3 -1
  29. data/lib/commonmarker.rb +70 -360
  30. data/lib/commonmarker/config.rb +1 -1
  31. data/lib/commonmarker/renderer.rb +91 -0
  32. data/lib/commonmarker/renderer/html_renderer.rb +149 -0
  33. data/lib/commonmarker/version.rb +1 -1
  34. data/test/benchinput.md +148414 -0
  35. data/test/benchmark.rb +13 -9
  36. data/test/progit/Gemfile +5 -0
  37. data/test/progit/README.md +9 -0
  38. data/test/progit/README.original.md +70 -0
  39. data/test/progit/Rakefile +285 -0
  40. data/test/progit/ar/01-introduction/01-chapter1.markdown +264 -0
  41. data/test/progit/ar/02-git-basics/01-chapter2.markdown +1124 -0
  42. data/test/progit/ar/NOTES +18 -0
  43. data/test/progit/ar/README +14 -0
  44. data/test/progit/az/01-introduction/01-chapter1.markdown +257 -0
  45. data/test/progit/az/02-git-basics/01-chapter2.markdown +1127 -0
  46. data/test/progit/az/03-git-branching/01-chapter3.markdown +598 -0
  47. data/test/progit/az/04-git-server/01-chapter4.markdown +861 -0
  48. data/test/progit/az/05-distributed-git/01-chapter5.markdown +897 -0
  49. data/test/progit/az/06-git-tools/01-chapter6.markdown +1126 -0
  50. data/test/progit/az/07-customizing-git/01-chapter7.markdown +937 -0
  51. data/test/progit/az/08-git-and-other-scms/01-chapter8.markdown +690 -0
  52. data/test/progit/az/09-git-internals/01-chapter9.markdown +977 -0
  53. data/test/progit/be/01-introduction/01-chapter1.markdown +257 -0
  54. data/test/progit/be/02-git-basics/01-chapter2.markdown +1126 -0
  55. data/test/progit/ca/01-introduction/01-chapter1.markdown +257 -0
  56. data/test/progit/ca/README.txt +1 -0
  57. data/test/progit/couchapp/Makefile +41 -0
  58. data/test/progit/couchapp/Readme.md +17 -0
  59. data/test/progit/couchapp/_id +1 -0
  60. data/test/progit/couchapp/shows/chapter.js +14 -0
  61. data/test/progit/couchapp/templates/foot.html +7 -0
  62. data/test/progit/couchapp/templates/head.html +51 -0
  63. data/test/progit/couchapp/vendor/markdown/showdown.js +420 -0
  64. data/test/progit/couchapp/vendor/mustache.js/mustache.js +302 -0
  65. data/test/progit/cs/01-introduction/01-chapter1.markdown +259 -0
  66. data/test/progit/cs/02-git-basics/01-chapter2.markdown +1225 -0
  67. data/test/progit/cs/03-git-branching/01-chapter3.markdown +606 -0
  68. data/test/progit/cs/04-git-server/01-chapter4.markdown +871 -0
  69. data/test/progit/cs/05-distributed-git/01-chapter5.markdown +914 -0
  70. data/test/progit/cs/06-git-tools/01-chapter6.markdown +1167 -0
  71. data/test/progit/cs/07-customizing-git/01-chapter7.markdown +940 -0
  72. data/test/progit/cs/08-git-and-other-scms/01-chapter8.markdown +700 -0
  73. data/test/progit/cs/09-git-internals/01-chapter9.markdown +1014 -0
  74. data/test/progit/de/01-introduction/01-chapter1.markdown +445 -0
  75. data/test/progit/de/02-git-basics/01-chapter2.markdown +1589 -0
  76. data/test/progit/de/03-git-branching/01-chapter3.markdown +964 -0
  77. data/test/progit/de/04-git-server/01-chapter4.markdown +1337 -0
  78. data/test/progit/de/05-distributed-git/01-chapter5.markdown +1329 -0
  79. data/test/progit/de/06-git-tools/01-chapter6.markdown +1502 -0
  80. data/test/progit/de/07-customizing-git/01-chapter7.markdown +1361 -0
  81. data/test/progit/de/08-git-and-other-scms/01-chapter8.markdown +919 -0
  82. data/test/progit/de/09-git-internals/01-chapter9.markdown +1361 -0
  83. data/test/progit/de/README.md +626 -0
  84. data/test/progit/ebooks/cover.png +0 -0
  85. data/test/progit/en/01-introduction/01-chapter1.markdown +263 -0
  86. data/test/progit/en/02-git-basics/01-chapter2.markdown +1228 -0
  87. data/test/progit/en/03-git-branching/01-chapter3.markdown +606 -0
  88. data/test/progit/en/04-git-server/01-chapter4.markdown +871 -0
  89. data/test/progit/en/05-distributed-git/01-chapter5.markdown +914 -0
  90. data/test/progit/en/06-git-tools/01-chapter6.markdown +1150 -0
  91. data/test/progit/en/07-customizing-git/01-chapter7.markdown +940 -0
  92. data/test/progit/en/08-git-and-other-scms/01-chapter8.markdown +700 -0
  93. data/test/progit/en/09-git-internals/01-chapter9.markdown +983 -0
  94. data/test/progit/eo/01-introduction/01-chapter1.markdown +257 -0
  95. data/test/progit/eo/02-git-basics/01-chapter2.markdown +1171 -0
  96. data/test/progit/epub/ProGit.css +28 -0
  97. data/test/progit/epub/title.png +0 -0
  98. data/test/progit/es-ni/01-introduction/01-chapter1.markdown +257 -0
  99. data/test/progit/es-ni/02-git-basics/01-chapter2.markdown +1127 -0
  100. data/test/progit/es/01-introduction/01-chapter1.markdown +262 -0
  101. data/test/progit/es/02-git-basics/01-chapter2.markdown +1165 -0
  102. data/test/progit/es/03-git-branching/01-chapter3.markdown +598 -0
  103. data/test/progit/es/04-git-server/01-chapter4.markdown +707 -0
  104. data/test/progit/es/05-distributed-git/01-chapter5.markdown +890 -0
  105. data/test/progit/es/06-git-tools/01-chapter6.markdown +1113 -0
  106. data/test/progit/es/07-customizing-git/01-chapter7.markdown +875 -0
  107. data/test/progit/es/08-git-and-other-scms/01-chapter8.markdown +686 -0
  108. data/test/progit/es/09-git-internals/01-chapter9.markdown +976 -0
  109. data/test/progit/es/NOTES +29 -0
  110. data/test/progit/es/README +3 -0
  111. data/test/progit/es/glosario-Benzirpi.txt +27 -0
  112. data/test/progit/es/omegat-Benzirpi.tmx +29075 -0
  113. data/test/progit/fa/01-introduction/01-chapter1.markdown +262 -0
  114. data/test/progit/fa/03-git-branching/01-chapter3.markdown +608 -0
  115. data/test/progit/fa/04-git-server/01-chapter4.markdown +872 -0
  116. data/test/progit/fa/NOTES.en-fa.md +143 -0
  117. data/test/progit/fa/README.md +7 -0
  118. data/test/progit/fi/01-introduction/01-chapter1.markdown +259 -0
  119. data/test/progit/fi/02-git-basics/01-chapter2.markdown +1171 -0
  120. data/test/progit/fi/NOTES +5 -0
  121. data/test/progit/figures-dia/fig0101.dia +617 -0
  122. data/test/progit/figures-dia/fig0102.dia +921 -0
  123. data/test/progit/figures-dia/fig0103.dia +1468 -0
  124. data/test/progit/figures-dia/fig0104.dia +1432 -0
  125. data/test/progit/figures-dia/fig0105.dia +1924 -0
  126. data/test/progit/figures-dia/fig0106.dia +562 -0
  127. data/test/progit/figures-dia/fig0201.dia +774 -0
  128. data/test/progit/figures-dia/fig0301.dia +2006 -0
  129. data/test/progit/figures-dia/fig0302.dia +2148 -0
  130. data/test/progit/figures-dia/fig0303.dia +719 -0
  131. data/test/progit/figures-dia/fig0304.dia +525 -0
  132. data/test/progit/figures-dia/fig0305.dia +622 -0
  133. data/test/progit/figures-dia/fig0306.dia +622 -0
  134. data/test/progit/figures-dia/fig0307.dia +719 -0
  135. data/test/progit/figures-dia/fig0308.dia +734 -0
  136. data/test/progit/figures-dia/fig0309.dia +831 -0
  137. data/test/progit/figures-dia/fig0310.dia +412 -0
  138. data/test/progit/figures-dia/fig0311.dia +493 -0
  139. data/test/progit/figures-dia/fig0312.dia +596 -0
  140. data/test/progit/figures-dia/fig0313.dia +774 -0
  141. data/test/progit/figures-dia/fig0314.dia +846 -0
  142. data/test/progit/figures-dia/fig0315.dia +787 -0
  143. data/test/progit/figures-dia/fig0316.dia +1078 -0
  144. data/test/progit/figures-dia/fig0317.dia +881 -0
  145. data/test/progit/figures-dia/fig0318.dia +968 -0
  146. data/test/progit/figures-dia/fig0319.dia +957 -0
  147. data/test/progit/figures-dia/fig0320.dia +1637 -0
  148. data/test/progit/figures-dia/fig0321.dia +1494 -0
  149. data/test/progit/figures-dia/fig0322.dia +1142 -0
  150. data/test/progit/figures-dia/fig0323.dia +1377 -0
  151. data/test/progit/figures-dia/fig0324.dia +1603 -0
  152. data/test/progit/figures-dia/fig0325.dia +2003 -0
  153. data/test/progit/figures-dia/fig0326.dia +2013 -0
  154. data/test/progit/figures-dia/fig0327.dia +687 -0
  155. data/test/progit/figures-dia/fig0328.dia +814 -0
  156. data/test/progit/figures-dia/fig0329.dia +793 -0
  157. data/test/progit/figures-dia/fig0330.dia +693 -0
  158. data/test/progit/figures-dia/fig0331.dia +1159 -0
  159. data/test/progit/figures-dia/fig0332.dia +1362 -0
  160. data/test/progit/figures-dia/fig0333.dia +1165 -0
  161. data/test/progit/figures-dia/fig0334.dia +1450 -0
  162. data/test/progit/figures-dia/fig0335.dia +994 -0
  163. data/test/progit/figures-dia/fig0336.dia +786 -0
  164. data/test/progit/figures-dia/fig0337.dia +1546 -0
  165. data/test/progit/figures-dia/fig0338.dia +1755 -0
  166. data/test/progit/figures-dia/fig0339.dia +1882 -0
  167. data/test/progit/figures-dia/fig0501.dia +456 -0
  168. data/test/progit/figures-dia/fig0502.dia +956 -0
  169. data/test/progit/figures-dia/fig0503.dia +915 -0
  170. data/test/progit/figures-dia/fig0504.dia +620 -0
  171. data/test/progit/figures-dia/fig0505.dia +744 -0
  172. data/test/progit/figures-dia/fig0506.dia +747 -0
  173. data/test/progit/figures-dia/fig0507.dia +895 -0
  174. data/test/progit/figures-dia/fig0508.dia +1122 -0
  175. data/test/progit/figures-dia/fig0509.dia +1243 -0
  176. data/test/progit/figures-dia/fig0510.dia +1240 -0
  177. data/test/progit/figures-dia/fig0511.dia +1201 -0
  178. data/test/progit/figures-dia/fig0512.dia +801 -0
  179. data/test/progit/figures-dia/fig0513.dia +1387 -0
  180. data/test/progit/figures-dia/fig0514.dia +1568 -0
  181. data/test/progit/figures-dia/fig0515.dia +1721 -0
  182. data/test/progit/figures-dia/fig0516.dia +997 -0
  183. data/test/progit/figures-dia/fig0517.dia +994 -0
  184. data/test/progit/figures-dia/fig0518.dia +1145 -0
  185. data/test/progit/figures-dia/fig0519.dia +992 -0
  186. data/test/progit/figures-dia/fig0520.dia +1240 -0
  187. data/test/progit/figures-dia/fig0521.dia +801 -0
  188. data/test/progit/figures-dia/fig0522.dia +922 -0
  189. data/test/progit/figures-dia/fig0523.dia +922 -0
  190. data/test/progit/figures-dia/fig0524.dia +1828 -0
  191. data/test/progit/figures-dia/fig0525.dia +2685 -0
  192. data/test/progit/figures-dia/fig0526.dia +717 -0
  193. data/test/progit/figures-dia/fig0527.dia +856 -0
  194. data/test/progit/figures-dia/fig0601.dia +790 -0
  195. data/test/progit/figures-dia/fig0702.dia +795 -0
  196. data/test/progit/figures-dia/fig0703.dia +795 -0
  197. data/test/progit/figures-dia/fig0901.dia +669 -0
  198. data/test/progit/figures-dia/fig0902.dia +834 -0
  199. data/test/progit/figures-dia/fig0903.dia +1483 -0
  200. data/test/progit/figures-dia/fig0904.dia +1728 -0
  201. data/test/progit/figures-dia/makeimages +25 -0
  202. data/test/progit/figures-source/progit.graffle +123108 -0
  203. data/test/progit/figures/18333fig0101-tn.png +0 -0
  204. data/test/progit/figures/18333fig0102-tn.png +0 -0
  205. data/test/progit/figures/18333fig0103-tn.png +0 -0
  206. data/test/progit/figures/18333fig0104-tn.png +0 -0
  207. data/test/progit/figures/18333fig0105-tn.png +0 -0
  208. data/test/progit/figures/18333fig0106-tn.png +0 -0
  209. data/test/progit/figures/18333fig0107-tn.png +0 -0
  210. data/test/progit/figures/18333fig0201-tn.png +0 -0
  211. data/test/progit/figures/18333fig0202-tn.png +0 -0
  212. data/test/progit/figures/18333fig0301-tn.png +0 -0
  213. data/test/progit/figures/18333fig0302-tn.png +0 -0
  214. data/test/progit/figures/18333fig0303-tn.png +0 -0
  215. data/test/progit/figures/18333fig0304-tn.png +0 -0
  216. data/test/progit/figures/18333fig0305-tn.png +0 -0
  217. data/test/progit/figures/18333fig0306-tn.png +0 -0
  218. data/test/progit/figures/18333fig0307-tn.png +0 -0
  219. data/test/progit/figures/18333fig0308-tn.png +0 -0
  220. data/test/progit/figures/18333fig0309-tn.png +0 -0
  221. data/test/progit/figures/18333fig0310-tn.png +0 -0
  222. data/test/progit/figures/18333fig0311-tn.png +0 -0
  223. data/test/progit/figures/18333fig0312-tn.png +0 -0
  224. data/test/progit/figures/18333fig0313-tn.png +0 -0
  225. data/test/progit/figures/18333fig0314-tn.png +0 -0
  226. data/test/progit/figures/18333fig0315-tn.png +0 -0
  227. data/test/progit/figures/18333fig0316-tn.png +0 -0
  228. data/test/progit/figures/18333fig0317-tn.png +0 -0
  229. data/test/progit/figures/18333fig0318-tn.png +0 -0
  230. data/test/progit/figures/18333fig0319-tn.png +0 -0
  231. data/test/progit/figures/18333fig0320-tn.png +0 -0
  232. data/test/progit/figures/18333fig0321-tn.png +0 -0
  233. data/test/progit/figures/18333fig0322-tn.png +0 -0
  234. data/test/progit/figures/18333fig0323-tn.png +0 -0
  235. data/test/progit/figures/18333fig0324-tn.png +0 -0
  236. data/test/progit/figures/18333fig0325-tn.png +0 -0
  237. data/test/progit/figures/18333fig0326-tn.png +0 -0
  238. data/test/progit/figures/18333fig0327-tn.png +0 -0
  239. data/test/progit/figures/18333fig0328-tn.png +0 -0
  240. data/test/progit/figures/18333fig0329-tn.png +0 -0
  241. data/test/progit/figures/18333fig0330-tn.png +0 -0
  242. data/test/progit/figures/18333fig0331-tn.png +0 -0
  243. data/test/progit/figures/18333fig0332-tn.png +0 -0
  244. data/test/progit/figures/18333fig0333-tn.png +0 -0
  245. data/test/progit/figures/18333fig0334-tn.png +0 -0
  246. data/test/progit/figures/18333fig0335-tn.png +0 -0
  247. data/test/progit/figures/18333fig0336-tn.png +0 -0
  248. data/test/progit/figures/18333fig0337-tn.png +0 -0
  249. data/test/progit/figures/18333fig0338-tn.png +0 -0
  250. data/test/progit/figures/18333fig0339-tn.png +0 -0
  251. data/test/progit/figures/18333fig0401-tn.png +0 -0
  252. data/test/progit/figures/18333fig0402-tn.png +0 -0
  253. data/test/progit/figures/18333fig0403-tn.png +0 -0
  254. data/test/progit/figures/18333fig0404-tn.png +0 -0
  255. data/test/progit/figures/18333fig0405-tn.png +0 -0
  256. data/test/progit/figures/18333fig0406-tn.png +0 -0
  257. data/test/progit/figures/18333fig0407-tn.png +0 -0
  258. data/test/progit/figures/18333fig0408-tn.png +0 -0
  259. data/test/progit/figures/18333fig0409-tn.png +0 -0
  260. data/test/progit/figures/18333fig0410-tn.png +0 -0
  261. data/test/progit/figures/18333fig0411-tn.png +0 -0
  262. data/test/progit/figures/18333fig0412-tn.png +0 -0
  263. data/test/progit/figures/18333fig0413-tn.png +0 -0
  264. data/test/progit/figures/18333fig0414-tn.png +0 -0
  265. data/test/progit/figures/18333fig0415-tn.png +0 -0
  266. data/test/progit/figures/18333fig0501-tn.png +0 -0
  267. data/test/progit/figures/18333fig0502-tn.png +0 -0
  268. data/test/progit/figures/18333fig0503-tn.png +0 -0
  269. data/test/progit/figures/18333fig0504-tn.png +0 -0
  270. data/test/progit/figures/18333fig0505-tn.png +0 -0
  271. data/test/progit/figures/18333fig0506-tn.png +0 -0
  272. data/test/progit/figures/18333fig0507-tn.png +0 -0
  273. data/test/progit/figures/18333fig0508-tn.png +0 -0
  274. data/test/progit/figures/18333fig0509-tn.png +0 -0
  275. data/test/progit/figures/18333fig0510-tn.png +0 -0
  276. data/test/progit/figures/18333fig0511-tn.png +0 -0
  277. data/test/progit/figures/18333fig0512-tn.png +0 -0
  278. data/test/progit/figures/18333fig0513-tn.png +0 -0
  279. data/test/progit/figures/18333fig0514-tn.png +0 -0
  280. data/test/progit/figures/18333fig0515-tn.png +0 -0
  281. data/test/progit/figures/18333fig0516-tn.png +0 -0
  282. data/test/progit/figures/18333fig0517-tn.png +0 -0
  283. data/test/progit/figures/18333fig0518-tn.png +0 -0
  284. data/test/progit/figures/18333fig0519-tn.png +0 -0
  285. data/test/progit/figures/18333fig0520-tn.png +0 -0
  286. data/test/progit/figures/18333fig0521-tn.png +0 -0
  287. data/test/progit/figures/18333fig0522-tn.png +0 -0
  288. data/test/progit/figures/18333fig0523-tn.png +0 -0
  289. data/test/progit/figures/18333fig0524-tn.png +0 -0
  290. data/test/progit/figures/18333fig0525-tn.png +0 -0
  291. data/test/progit/figures/18333fig0526-tn.png +0 -0
  292. data/test/progit/figures/18333fig0527-tn.png +0 -0
  293. data/test/progit/figures/18333fig0601-tn.png +0 -0
  294. data/test/progit/figures/18333fig0701-tn.png +0 -0
  295. data/test/progit/figures/18333fig0702-tn.png +0 -0
  296. data/test/progit/figures/18333fig0703-tn.png +0 -0
  297. data/test/progit/figures/18333fig0901-tn.png +0 -0
  298. data/test/progit/figures/18333fig0902-tn.png +0 -0
  299. data/test/progit/figures/18333fig0903-tn.png +0 -0
  300. data/test/progit/figures/18333fig0904-tn.png +0 -0
  301. data/test/progit/fr/01-introduction/01-chapter1.markdown +371 -0
  302. data/test/progit/fr/02-git-basics/01-chapter2.markdown +1378 -0
  303. data/test/progit/fr/03-git-branching/01-chapter3.markdown +781 -0
  304. data/test/progit/fr/04-git-server/01-chapter4.markdown +1141 -0
  305. data/test/progit/fr/05-distributed-git/01-chapter5.markdown +1163 -0
  306. data/test/progit/fr/06-git-tools/01-chapter6.markdown +1356 -0
  307. data/test/progit/fr/07-customizing-git/01-chapter7.markdown +1200 -0
  308. data/test/progit/fr/08-git-and-other-scms/01-chapter8.markdown +832 -0
  309. data/test/progit/fr/09-git-internals/01-chapter9.markdown +1228 -0
  310. data/test/progit/fr/NOTES.fr-fr.markdown +1 -0
  311. data/test/progit/fr/NOTES.fr-fr.md +127 -0
  312. data/test/progit/fr/README.md +43 -0
  313. data/test/progit/fr/glossaire-git.adoc +108 -0
  314. data/test/progit/hi/01-introduction/01-chapter1.markdown +7 -0
  315. data/test/progit/hu/01-introduction/01-chapter1.markdown +257 -0
  316. data/test/progit/id/01-introduction/01-chapter1.markdown +257 -0
  317. data/test/progit/id/02-git-basics/01-chapter2.markdown +1127 -0
  318. data/test/progit/id/03-git-branching/01-chapter3.markdown +598 -0
  319. data/test/progit/it/01-introduction/01-chapter1.markdown +263 -0
  320. data/test/progit/it/02-git-basics/01-chapter2.markdown +1227 -0
  321. data/test/progit/it/03-git-branching/01-chapter3.markdown +598 -0
  322. data/test/progit/it/04-git-server/01-chapter4.markdown +864 -0
  323. data/test/progit/it/05-distributed-git/01-chapter5.markdown +897 -0
  324. data/test/progit/it/06-git-tools/01-chapter6.markdown +1144 -0
  325. data/test/progit/it/07-customizing-git/01-chapter7.markdown +606 -0
  326. data/test/progit/it/08-git-and-other-scms/01-chapter8.markdown +707 -0
  327. data/test/progit/it/09-git-internals/01-chapter9.markdown +1000 -0
  328. data/test/progit/ja/01-introduction/01-chapter1.markdown +260 -0
  329. data/test/progit/ja/02-git-basics/01-chapter2.markdown +1221 -0
  330. data/test/progit/ja/03-git-branching/01-chapter3.markdown +604 -0
  331. data/test/progit/ja/04-git-server/01-chapter4.markdown +863 -0
  332. data/test/progit/ja/05-distributed-git/01-chapter5.markdown +908 -0
  333. data/test/progit/ja/06-git-tools/01-chapter6.markdown +1133 -0
  334. data/test/progit/ja/07-customizing-git/01-chapter7.markdown +936 -0
  335. data/test/progit/ja/08-git-and-other-scms/01-chapter8.markdown +690 -0
  336. data/test/progit/ja/09-git-internals/01-chapter9.markdown +984 -0
  337. data/test/progit/ja/README.md +58 -0
  338. data/test/progit/ja/translation glossaries.txt +33 -0
  339. data/test/progit/ko/01-introduction/01-chapter1.markdown +258 -0
  340. data/test/progit/ko/02-git-basics/01-chapter2.markdown +1181 -0
  341. data/test/progit/ko/03-git-branching/01-chapter3.markdown +612 -0
  342. data/test/progit/ko/04-git-server/01-chapter4.markdown +867 -0
  343. data/test/progit/ko/05-distributed-git/01-chapter5.markdown +913 -0
  344. data/test/progit/ko/06-git-tools/01-chapter6.markdown +1142 -0
  345. data/test/progit/ko/07-customizing-git/01-chapter7.markdown +935 -0
  346. data/test/progit/ko/08-git-and-other-scms/01-chapter8.markdown +688 -0
  347. data/test/progit/ko/09-git-internals/01-chapter9.markdown +976 -0
  348. data/test/progit/ko/README.md +75 -0
  349. data/test/progit/ko/translation_guide.txt +65 -0
  350. data/test/progit/latex/README +27 -0
  351. data/test/progit/latex/config.yml +144 -0
  352. data/test/progit/latex/makepdf +207 -0
  353. data/test/progit/latex/template.tex +155 -0
  354. data/test/progit/makeebooks +125 -0
  355. data/test/progit/makepdfs +47 -0
  356. data/test/progit/mk/01-introduction/01-chapter1.markdown +258 -0
  357. data/test/progit/mk/02-git-basics/01-chapter2.markdown +1125 -0
  358. data/test/progit/mk/03-git-branching/01-chapter3.markdown +598 -0
  359. data/test/progit/mk/05-distributed-git/01-chapter5.markdown +897 -0
  360. data/test/progit/nl/01-introduction/01-chapter1.markdown +296 -0
  361. data/test/progit/nl/02-git-basics/01-chapter2.markdown +1253 -0
  362. data/test/progit/nl/03-git-branching/01-chapter3.markdown +642 -0
  363. data/test/progit/nl/04-git-server/01-chapter4.markdown +902 -0
  364. data/test/progit/nl/05-distributed-git/01-chapter5.markdown +953 -0
  365. data/test/progit/nl/06-git-tools/01-chapter6.markdown +1177 -0
  366. data/test/progit/nl/07-customizing-git/01-chapter7.markdown +974 -0
  367. data/test/progit/nl/08-git-and-other-scms/01-chapter8.markdown +725 -0
  368. data/test/progit/nl/09-git-internals/01-chapter9.markdown +1013 -0
  369. data/test/progit/no-nb/01-introduction/01-chapter1.markdown +261 -0
  370. data/test/progit/no-nb/02-git-basics/01-chapter2.markdown +1225 -0
  371. data/test/progit/no-nb/03-git-branching/01-chapter3.markdown +606 -0
  372. data/test/progit/no-nb/04-git-server/01-chapter4.markdown +867 -0
  373. data/test/progit/no-nb/05-distributed-git/01-chapter5.markdown +914 -0
  374. data/test/progit/no-nb/06-git-tools/01-chapter6.markdown +1144 -0
  375. data/test/progit/no-nb/07-customizing-git/01-chapter7.markdown +936 -0
  376. data/test/progit/no-nb/08-git-and-other-scms/01-chapter8.markdown +689 -0
  377. data/test/progit/no-nb/09-git-internals/01-chapter9.markdown +977 -0
  378. data/test/progit/no-nb/README +2 -0
  379. data/test/progit/pl/01-introduction/01-chapter1.markdown +257 -0
  380. data/test/progit/pl/02-git-basics/02-chapter2.markdown +1128 -0
  381. data/test/progit/pl/03-git-branching/01-chapter3.markdown +598 -0
  382. data/test/progit/pl/04-git-server/01-chapter4.markdown +897 -0
  383. data/test/progit/pl/05-distributed-git/01-chapter5.markdown +1278 -0
  384. data/test/progit/pl/06-git-tools/01-chapter6.markdown +1550 -0
  385. data/test/progit/pl/07-customizing-git/01-chapter7.markdown +1058 -0
  386. data/test/progit/pl/08-git-and-other-scms/01-chapter8.markdown +948 -0
  387. data/test/progit/pl/09-git-internals/01-chapter9.markdown +1382 -0
  388. data/test/progit/pl/translation-guidelines.txt +70 -0
  389. data/test/progit/pt-br/01-introduction/01-chapter1.markdown +256 -0
  390. data/test/progit/pt-br/02-git-basics/01-chapter2.markdown +1127 -0
  391. data/test/progit/pt-br/03-git-branching/01-chapter3.markdown +596 -0
  392. data/test/progit/pt-br/04-git-server/01-chapter4.markdown +888 -0
  393. data/test/progit/pt-br/05-distributed-git/01-chapter5.markdown +896 -0
  394. data/test/progit/pt-br/06-git-tools/01-chapter6.markdown +1122 -0
  395. data/test/progit/pt-br/07-customizing-git/01-chapter7.markdown +932 -0
  396. data/test/progit/pt-br/08-git-and-other-scms/01-chapter8.markdown +691 -0
  397. data/test/progit/pt-br/09-git-internals/01-chapter9.markdown +978 -0
  398. data/test/progit/pt-br/figures-dia/fig0101.dia +617 -0
  399. data/test/progit/pt-br/figures-dia/fig0102.dia +921 -0
  400. data/test/progit/pt-br/figures-dia/fig0103.dia +1468 -0
  401. data/test/progit/pt-br/figures-dia/fig0104.dia +1432 -0
  402. data/test/progit/pt-br/figures-dia/fig0105.dia +1924 -0
  403. data/test/progit/pt-br/figures-dia/fig0106.dia +562 -0
  404. data/test/progit/pt-br/figures-dia/fig0201.dia +776 -0
  405. data/test/progit/pt-br/figures-dia/fig0301.dia +2006 -0
  406. data/test/progit/pt-br/figures-dia/fig0302.dia +2148 -0
  407. data/test/progit/pt-br/figures-dia/fig0316.dia +1079 -0
  408. data/test/progit/pt-br/figures-dia/fig0322.dia +1142 -0
  409. data/test/progit/pt-br/figures-dia/fig0323.dia +1407 -0
  410. data/test/progit/pt-br/figures-dia/fig0324.dia +1603 -0
  411. data/test/progit/pt-br/figures-dia/fig0325.dia +2003 -0
  412. data/test/progit/pt-br/figures-dia/fig0326.dia +2013 -0
  413. data/test/progit/pt-br/figures-dia/fig0336.dia +786 -0
  414. data/test/progit/pt-br/figures-dia/fig0337.dia +1546 -0
  415. data/test/progit/pt-br/figures-dia/fig0338.dia +1755 -0
  416. data/test/progit/pt-br/figures-dia/fig0339.dia +1882 -0
  417. data/test/progit/pt-br/figures-dia/fig0501.dia +456 -0
  418. data/test/progit/pt-br/figures-dia/fig0502.dia +965 -0
  419. data/test/progit/pt-br/figures-dia/fig0503.dia +914 -0
  420. data/test/progit/pt-br/figures-dia/fig0511.dia +1201 -0
  421. data/test/progit/pt-br/figures-dia/fig0515.dia +1721 -0
  422. data/test/progit/pt-br/figures-dia/fig0702.dia +795 -0
  423. data/test/progit/pt-br/figures-dia/fig0703.dia +795 -0
  424. data/test/progit/pt-br/figures-dia/fig0901.dia +669 -0
  425. data/test/progit/pt-br/figures-dia/fig0902.dia +834 -0
  426. data/test/progit/pt-br/figures-dia/fig0903.dia +1483 -0
  427. data/test/progit/pt-br/figures-dia/fig0904.dia +1728 -0
  428. data/test/progit/ro/01-introduction/01-chapter1.markdown +257 -0
  429. data/test/progit/ru/01-introduction/01-chapter1.markdown +259 -0
  430. data/test/progit/ru/02-git-basics/01-chapter2.markdown +1155 -0
  431. data/test/progit/ru/03-git-branching/01-chapter3.markdown +598 -0
  432. data/test/progit/ru/04-git-server/01-chapter4.markdown +854 -0
  433. data/test/progit/ru/05-distributed-git/01-chapter5.markdown +897 -0
  434. data/test/progit/ru/06-git-tools/01-chapter6.markdown +1126 -0
  435. data/test/progit/ru/07-customizing-git/01-chapter7.markdown +938 -0
  436. data/test/progit/ru/08-git-and-other-scms/01-chapter8.markdown +691 -0
  437. data/test/progit/ru/09-git-internals/01-chapter9.markdown +977 -0
  438. data/test/progit/ru/Glossary +38 -0
  439. data/test/progit/ru/README +12 -0
  440. data/test/progit/ru/figures-dia/fig0101.dia +647 -0
  441. data/test/progit/ru/figures-dia/fig0102.dia +1009 -0
  442. data/test/progit/ru/figures-dia/fig0103.dia +1468 -0
  443. data/test/progit/ru/figures-dia/fig0104.dia +1432 -0
  444. data/test/progit/ru/figures-dia/fig0105.dia +1924 -0
  445. data/test/progit/ru/figures-dia/fig0106.dia +561 -0
  446. data/test/progit/ru/figures-dia/fig0201.dia +774 -0
  447. data/test/progit/ru/figures-dia/fig0322.dia +1182 -0
  448. data/test/progit/ru/figures-dia/fig0323.dia +1457 -0
  449. data/test/progit/ru/figures-dia/fig0324.dia +1698 -0
  450. data/test/progit/ru/figures-dia/fig0325.dia +2101 -0
  451. data/test/progit/ru/figures-dia/fig0326.dia +2111 -0
  452. data/test/progit/ru/figures-dia/fig0336.dia +786 -0
  453. data/test/progit/ru/figures-dia/fig0337.dia +1546 -0
  454. data/test/progit/ru/figures-dia/fig0338.dia +1755 -0
  455. data/test/progit/ru/figures-dia/fig0339.dia +1882 -0
  456. data/test/progit/ru/figures-dia/fig0501.dia +477 -0
  457. data/test/progit/ru/figures-dia/fig0502.dia +1063 -0
  458. data/test/progit/ru/figures-dia/fig0503.dia +915 -0
  459. data/test/progit/ru/figures-dia/fig0511.dia +1201 -0
  460. data/test/progit/ru/figures-dia/fig0515.dia +1741 -0
  461. data/test/progit/ru/figures-dia/fig0702.dia +851 -0
  462. data/test/progit/ru/figures-dia/fig0703.dia +851 -0
  463. data/test/progit/sr/01-introduction/01-chapter1.markdown +257 -0
  464. data/test/progit/summary.rb +29 -0
  465. data/test/progit/th/01-introduction/01-chapter1.markdown +257 -0
  466. data/test/progit/th/02-git-basics/01-chapter2.markdown +1126 -0
  467. data/test/progit/th/README.md +47 -0
  468. data/test/progit/tr/01-introduction/01-chapter1.markdown +258 -0
  469. data/test/progit/tr/02-git-basics/01-chapter2.markdown +1129 -0
  470. data/test/progit/tr/03-git-branching/01-chapter3.markdown +598 -0
  471. data/test/progit/tr/04-git-server/01-chapter4.markdown +73 -0
  472. data/test/progit/tr/05-distributed-git/01-chapter5.markdown +215 -0
  473. data/test/progit/uk/01-introduction/01-chapter1.markdown +522 -0
  474. data/test/progit/vi/01-introduction/01-chapter1.markdown +259 -0
  475. data/test/progit/vi/02-git-basics/01-chapter2.markdown +1172 -0
  476. data/test/progit/vi/03-git-branching/01-chapter3.markdown +598 -0
  477. data/test/progit/zh-tw/01-introduction/01-chapter1.markdown +259 -0
  478. data/test/progit/zh-tw/02-git-basics/01-chapter2.markdown +1183 -0
  479. data/test/progit/zh-tw/03-git-branching/01-chapter3.markdown +604 -0
  480. data/test/progit/zh-tw/04-git-server/01-chapter4.markdown +866 -0
  481. data/test/progit/zh-tw/05-distributed-git/01-chapter5.markdown +912 -0
  482. data/test/progit/zh-tw/06-git-tools/01-chapter6.markdown +1139 -0
  483. data/test/progit/zh-tw/07-customizing-git/01-chapter7.markdown +932 -0
  484. data/test/progit/zh-tw/08-git-and-other-scms/01-chapter8.markdown +689 -0
  485. data/test/progit/zh-tw/09-git-internals/01-chapter9.markdown +977 -0
  486. data/test/progit/zh/01-introduction/01-chapter1.markdown +259 -0
  487. data/test/progit/zh/02-git-basics/01-chapter2.markdown +1177 -0
  488. data/test/progit/zh/03-git-branching/01-chapter3.markdown +604 -0
  489. data/test/progit/zh/04-git-server/01-chapter4.markdown +866 -0
  490. data/test/progit/zh/05-distributed-git/01-chapter5.markdown +912 -0
  491. data/test/progit/zh/06-git-tools/01-chapter6.markdown +1125 -0
  492. data/test/progit/zh/07-customizing-git/01-chapter7.markdown +935 -0
  493. data/test/progit/zh/08-git-and-other-scms/01-chapter8.markdown +689 -0
  494. data/test/progit/zh/09-git-internals/01-chapter9.markdown +976 -0
  495. data/test/spec_tests.json +4382 -4070
  496. data/test/test_basics.rb +1 -1
  497. data/test/test_helper.rb +1 -0
  498. data/test/test_maliciousness.rb +4 -2
  499. data/test/test_pathological_inputs.rb +31 -30
  500. data/test/test_spec.rb +5 -4
  501. metadata +972 -4
@@ -0,0 +1,1200 @@
1
+ # Personnalisation de Git #
2
+
3
+ Jusqu'ici, nous avons traité les bases du fonctionnement et de l'utilisation de Git et introduit un certain nombre d'outils fournis par Git pour travailler plus facilement et plus efficacement.
4
+ Dans ce chapitre, nous aborderons quelques opérations permettant d'utiliser Git de manière plus personnalisée en vous présentant quelques paramètres de configuration importants et le système d'interceptions.
5
+ Grâce à ces outils, il devient enfantin de faire fonctionner Git exactement comme vous, votre société ou votre communauté en avez besoin.
6
+
7
+ ## Configuration de Git ##
8
+
9
+ Comme vous avez pu l'entrevoir au chapitre 1, vous pouvez spécifier les paramètres de configuration de Git avec la commande `git config`.
10
+ Une des premières choses que vous avez faites a été de paramétrer votre nom et votre adresse e-mail :
11
+
12
+ $ git config --global user.name "John Doe"
13
+ $ git config --global user.email johndoe@example.com
14
+
15
+ À présent, vous allez apprendre quelques unes des options similaires les plus intéressantes pour paramétrer votre usage de Git.
16
+
17
+ Vous avez vu des détails de configuration simple de Git au premier chapitre, mais nous allons les réviser.
18
+ Git utilise une série de fichiers de configuration pour déterminer son comportement selon votre personnalisation.
19
+ Le premier endroit que Git visite est le fichier `/etc/gitconfig` qui contient des valeurs pour tous les utilisateurs du système et tous leurs dépôts.
20
+ Si vous passez l'option `--system` à `git config`, il lit et écrit ce fichier.
21
+
22
+ L'endroit suivant visité par Git est le fichier `~/.gitconfig` qui est spécifique à chaque utilisateur.
23
+ Vous pouvez faire lire et écrire Git dans ce fichier au moyen de l'option `--global`.
24
+
25
+ Enfin, Git recherche des valeurs de configuration dans le fichier de configuration du répertoire Git (`.git/config`) du dépôt en cours d'utilisation.
26
+ Ces valeurs sont spécifiques à un unique dépôt.
27
+ Chaque niveau surcharge le niveau précédent, ce qui signifie que les valeurs dans `.git/config` écrasent celles dans `/etc/gitconfig`.
28
+ Vous pouvez positionner ces valeurs manuellement en éditant le fichier et en utilisant la syntaxe correcte, mais il reste généralement plus facile de lancer la commande `git config`.
29
+
30
+ ### Configuration de base d'un client ###
31
+
32
+ Les options de configuration reconnues par Git tombent dans deux catégories : côté client et côté serveur.
33
+ La grande majorité se situe côté client pour coller à vos préférences personnelles de travail.
34
+ Parmi les tonnes d'options disponibles, seules les plus communes ou affectant significativement la manière de travailler seront couvertes.
35
+ De nombreuses options ne s'avèrent utiles qu'en de rares cas et ne seront pas traitées.
36
+ Pour voir la liste de toutes les options que votre version de Git reconnaît, vous pouvez lancer :
37
+
38
+ $ git config --help
39
+
40
+ La page de manuel pour `git config` détaille aussi les options disponibles.
41
+
42
+ #### core.editor ####
43
+
44
+ Par défaut, Git utilise votre éditeur par défaut ou se replie sur l'éditeur Vi pour la création et l'édition des messages de validation et d'étiquetage.
45
+ Pour modifier ce programme par défaut pour un autre, vous pouvez utiliser le paramètre `core.editor` :
46
+
47
+ $ git config --global core.editor emacs
48
+
49
+ Maintenant, quel que soit votre éditeur par défaut, Git démarrera Emacs pour éditer les messages.
50
+
51
+ #### commit.template ####
52
+
53
+ Si vous réglez ceci sur le chemin d'un fichier sur votre système, Git utilisera ce fichier comme message par défaut quand vous validez.
54
+ Par exemple, supposons que vous créiez un fichier modèle dans `$HOME/.gitmessage.txt` qui ressemble à ceci :
55
+
56
+ ligne de sujet
57
+
58
+ description
59
+
60
+ [ticket: X]
61
+
62
+ Pour indiquer à Git de l'utiliser pour le message par défaut qui apparaîtra dans votre éditeur quand vous lancerez `git commit`, réglez le paramètre de configuration `commit.template` :
63
+
64
+ $ git config --global commit.template $HOME/.gitmessage.txt
65
+ $ git commit
66
+
67
+ Ainsi, votre éditeur ouvrira quelque chose ressemblant à ceci comme modèle de message de validation :
68
+
69
+ ligne de sujet
70
+
71
+ description
72
+
73
+ [ticket: X]
74
+ # Please enter the commit message for your changes. Lines starting
75
+ # with '#' will be ignored, and an empty message aborts the commit.
76
+ # On branch master
77
+ # Changes to be committed:
78
+ # (use "git reset HEAD <file>..." to unstage)
79
+ #
80
+ # modified: lib/test.rb
81
+ #
82
+ ~
83
+ ~
84
+ ".git/COMMIT_EDITMSG" 14L, 297C
85
+
86
+ Si vous avez une règle de messages de validation, placez un modèle de cette règle sur votre système et configurez Git pour qu'il l'utilise par défaut, cela améliorera les chances que cette règle soit effectivement suivie.
87
+
88
+ #### core.pager ####
89
+
90
+ Le paramètre `core.pager` détermine quel *pager* est utilisé lorsque des pages de Git sont émises, par exemple lors d'un `log` ou d'un `diff`.
91
+ Vous pouvez le fixer à `more` ou à votre *pager* favori (par défaut, il vaut `less`) ou vous pouvez le désactiver en fixant sa valeur à une chaîne vide :
92
+
93
+ $ git config --global core.pager ''
94
+
95
+ Si vous lancez cela, Git affichera la totalité du résultat de toutes les commandes d'une traite, quelle que soit sa longueur.
96
+
97
+ #### user.signingkey ####
98
+
99
+ Si vous faîtes des étiquettes annotées signées (comme décrit au chapitre 2), simplifiez-vous la vie en définissant votre clé GPG de signature en paramètre de configuration.
100
+ Définissez votre ID de clé ainsi :
101
+
102
+ $ git config --global user.signingkey <gpg-key-id>
103
+
104
+ Maintenant, vous pouvez signer vos étiquettes sans devoir spécifier votre clé à chaque fois que vous utilisez la commande `git tag` :
105
+
106
+ $ git tag -s <nom-étiquette>
107
+
108
+ #### core.excludesfile ####
109
+
110
+ Comme décrit au chapitre 2, vous pouvez ajouter des patrons dans le fichier `.gitignore` de votre projet pour indiquer à Git de ne pas considérer certains fichiers comme non suivis ou pour éviter de les indexer lorsque vous lancez `git add` sur eux.
111
+ Cependant, si vous souhaitez qu'un autre fichier à l'extérieur du projet contienne ces informations ou en avoir d'autres supplémentaires, vous pouvez indiquer à Git où ce fichier se trouve grâce au paramètre `core.excludesfile`.
112
+ Fixez-le simplement sur le chemin du fichier qui contient les informations similaires à celles de `.gitignore`.
113
+
114
+ #### help.autocorrect ####
115
+
116
+ Si vous avez fait une faute de frappe en tapant une commande dans Git 1.6, il vous affichera une liste de commandes ressemblantes :
117
+
118
+ $ git com
119
+ git: 'com' is not a git-command. See 'git --help'.
120
+
121
+ Did you mean this?
122
+ commit
123
+
124
+ Si vous positionnez le paramètre `help.autocorrect` à 1, Git lancera automatiquement de lui-même la commande si une seule commande ressemblante a été trouvée.
125
+
126
+ ### Couleurs dans Git ###
127
+
128
+ Git sait coloriser ses affichages dans votre terminal, ce qui peut faciliter le parcours visuel des résultats.
129
+ Un certain nombre d'options peuvent vous aider à régler la colorisation à votre goût.
130
+
131
+ #### color.ui ####
132
+
133
+ Git colorise automatiquement la plupart de ses affichages si vous le lui demandez.
134
+ Vous pouvez néanmoins vouloir être plus précis sur ce que vous souhaitez voir colorisé et comment vous le souhaitez.
135
+ Pour activer toute la colorisation par défaut, fixez `color.ui` à `true` :
136
+
137
+ $ git config --global color.ui true
138
+
139
+ Avec cette valeur du paramètre, Git colorise sa sortie si celle-ci est destinée à un terminal.
140
+ D'autres réglages possibles sont `false` qui désactive complètement la colorisation et `always` qui active la colorisation, même si vous envoyez la commande Git dans un fichier ou l'entrée d'une autre commande.
141
+ Ce réglage a été ajouté dans Git 1.5.5.
142
+ Si vous avez une version antérieure, vous devrez spécifier les règles de colorisation individuellement.
143
+
144
+ `color.ui = always` est rarement utile.
145
+ Dans la plupart des cas, si vous tenez vraiment à coloriser vos sorties redirigées, vous pourrez passer le drapeau `--color` à la commande Git pour la forcer à utiliser les codes de couleur.
146
+ Le réglage `color.ui = true` est donc le plus utilisé.
147
+
148
+ #### `color.*` ####
149
+
150
+ Si vous souhaitez être plus spécifique concernant les commandes colorisées ou si vous avez une ancienne version, Git propose des paramètres de colorisation par action.
151
+ Chacun peut être fixé à `true`, `false` ou `always`.
152
+
153
+ color.branch
154
+ color.diff
155
+ color.interactive
156
+ color.status
157
+
158
+ De plus, chacun d'entre eux dispose d'un sous-ensemble de paramètres qui permettent de surcharger les couleurs pour des parties des affichages.
159
+ Par exemple, pour régler les couleurs de méta-informations du diff avec une écriture en bleu gras (*bold* en anglais) sur fond noir :
160
+
161
+ $ git config --global color.diff.meta "blue black bold"
162
+
163
+ La couleur peut prendre les valeurs suivantes : *normal*, *black*, *red*, *green*, *yellow*, *blue*, *magenta*, *cyan* ou *white*.
164
+ Si vous souhaitez ajouter un attribut de casse, les valeurs disponibles sont *bold* (gras), *dim* (léger), *ul* (*underlined*, souligné), *blink* (clignotant) et *reverse* (inversé).
165
+
166
+ Référez-vous à la page du manuel de `git config` pour tous les sous-réglages disponibles.
167
+
168
+ ### Outils externes de fusion et de différence ###
169
+
170
+ Bien que Git ait une implémentation interne de diff que vous avez déjà utilisée, vous pouvez sélectionner à la place un outil externe.
171
+ Vous pouvez aussi sélectionner un outil graphique pour la fusion et la résolution de conflit au lieu de devoir résoudre les conflits manuellement.
172
+ Je démontrerai le paramétrage avec Perforce Merge Tool (P4Merge) pour visualiser vos différences et résoudre vos fusions parce que c'est un outil graphique agréable et gratuit.
173
+
174
+ Si vous voulez l'essayer, P4Merge fonctionne sur tous les principaux systèmes d'exploitation.
175
+ Dans cet exemple, je vais utiliser la forme des chemins usitée sur Mac et Linux.
176
+ Pour Windows, vous devrez changer `/usr/local/bin` en un chemin d'exécution d'un programme de votre environnement.
177
+
178
+ Vous pouvez télécharger P4Merge ici :
179
+
180
+ http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools
181
+
182
+ Pour commencer, créez un script d'appel externe pour lancer vos commandes.
183
+ Je vais utiliser le chemin Mac pour l'exécutable ; dans d'autres systèmes, il résidera où votre binaire `p4merge` a été installé.
184
+ Créez un script enveloppe nommé `extMerge` qui appelle votre binaire avec tous les arguments fournis :
185
+
186
+ $ cat /usr/local/bin/extMerge
187
+ #!/bin/sh
188
+ /Applications/p4merge.app/Contents/MacOS/p4merge $*
189
+
190
+ L'enveloppe diff s'assure que sept arguments ont été fournis et en passe deux à votre script de fusion.
191
+ Par défaut, Git passe au programme de diff les arguments suivants :
192
+
193
+ chemin ancien-fichier ancien-hex ancien-mode nouveau-fichier nouveau-hex nouveau-mode
194
+
195
+ Comme seuls les arguments `ancien-fichier` et `nouveau-fichier` sont nécessaires, vous utilisez le script d'enveloppe pour passer ceux dont vous avez besoin.
196
+
197
+ $ cat /usr/local/bin/extDiff
198
+ #!/bin/sh
199
+ [ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"
200
+
201
+ Vous devez aussi vous assurer que ces fichiers sont exécutables :
202
+
203
+ $ sudo chmod +x /usr/local/bin/extMerge
204
+ $ sudo chmod +x /usr/local/bin/extDiff
205
+
206
+ À présent, vous pouvez régler votre fichier de configuration pour utiliser vos outils personnalisés de résolution de fusion et de différence.
207
+ Pour cela, il faut un certain nombre de personnalisations : `merge.tool` pour indiquer à Git quelle stratégie utiliser, `mergetool.*.cmd` pour spécifier comment lancer cette commande, `mergetool.trustExitCode` pour indiquer à Git si le code de sortie du programme indique une résolution de fusion réussie ou non et `diff.external` pour indiquer à Git quelle commande lancer pour les différences.
208
+ Ainsi, vous pouvez lancer les quatre commandes :
209
+
210
+ $ git config --global merge.tool extMerge
211
+ $ git config --global mergetool.extMerge.cmd \
212
+ 'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
213
+ $ git config --global mergetool.trustExitCode false
214
+ $ git config --global diff.external extDiff
215
+
216
+ ou vous pouvez éditer votre fichier `~/.gitconfig` pour y ajouter ces lignes :
217
+
218
+ [merge]
219
+ tool = extMerge
220
+ [mergetool "extMerge"]
221
+ cmd = extMerge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
222
+ trustExitCode = false
223
+ [diff]
224
+ external = extDiff
225
+
226
+ Après avoir réglé tout ceci, si vous lancez des commandes de diff telles que celle-ci :
227
+
228
+ $ git diff 32d1776b1^ 32d1776b1
229
+
230
+ Au lieu d'obtenir la sortie du diff dans le terminal, Git lance P4Merge, ce qui ressemble à la figure 7-1.
231
+
232
+ Insert 18333fig0701.png
233
+ Figure 7-1. L'outil de fusion P4Merge.
234
+
235
+ Si vous essayez de fusionner deux branches et créez des conflits de fusion, vous pouvez lancer la commande `git mergetool` qui démarrera P4Merge pour vous laisser résoudre les conflits au moyen d'un outil graphique.
236
+
237
+ Le point agréable avec cette méthode d'enveloppe est que vous pouvez changer facilement d'outils de diff et de fusion.
238
+ Par exemple, pour changer vos outils `extDiff` et `extMerge` pour une utilisation de l'outil KDiff3, il vous suffit d'éditer le fichier `extMerge` :
239
+
240
+ $ cat /usr/local/bin/extMerge
241
+ #!/bin/sh
242
+ /Applications/kdiff3.app/Contents/MacOS/kdiff3 $*
243
+
244
+ À présent, Git va utiliser l'outil KDiff3 pour visualiser les différences et résoudre les conflits de fusion.
245
+
246
+ Git est livré préréglé avec un certain nombre d'autres outils de résolution de fusion pour vous éviter d'avoir à gérer la configuration `cmd`.
247
+ Vous pouvez sélectionner votre outil de fusion parmi `kdiff3`, `opendiff`, `tkdiff`, `meld`, `xxdiff`, `emerge`, `vimdiff` ou `gvimdiff`.
248
+ Si KDiff3 ne vous intéresse pas pour gérer les différences mais seulement pour la résolution de fusion et qu'il est présent dans votre chemin d'exécution, vous pouvez lancer :
249
+
250
+ $ git config --global merge.tool kdiff3
251
+
252
+ Si vous lancez ceci au lieu de modifier les fichiers `extMerge` ou `extDiff`, Git utilisera KDif3 pour les résolutions de fusion et l'outil diff normal de Git pour les différences.
253
+
254
+ ### Formatage et espaces blancs ###
255
+
256
+ Les problèmes de formatage et de blancs sont parmi les plus subtils et frustrants que les développeurs rencontrent lorsqu'ils collaborent, spécifiquement d'une plate-forme à l'autre.
257
+ Il est très facile d'introduire des modifications subtiles de blancs lors de soumission de patchs ou d'autres modes de collaboration, car les éditeurs de textes les insèrent silencieusement ou les programmeurs Windows ajoutent des retours chariot à la fin des lignes qu'il modifient.
258
+ Git dispose de quelques options de configuration pour traiter ces problèmes.
259
+
260
+ #### core.autocrlf ####
261
+
262
+ Si vous programmez vous-même sous Windows ou si vous utilisez un autre système d'exploitation mais devez travailler avec des personnes travaillant sous Windows, vous rencontrerez à un moment ou à un autre des problèmes de caractères de fin de ligne.
263
+ Ceci est dû au fait que Windows utilise pour marquer les fins de ligne dans ses fichiers un caractère « retour chariot » (*carriage return*, CR) suivi d'un caractère « saut de ligne » (*line feed*, LF), tandis que Mac et Linux utilisent seulement le caractère « saut de ligne ».
264
+ C'est un cas subtil mais incroyablement ennuyeux de problème généré par la collaboration inter plate-forme.
265
+
266
+ Git peut gérer ce cas en convertissant automatiquement les fins de ligne CRLF en LF lorsque vous validez, et inversement lorsqu'il extrait des fichiers sur votre système.
267
+ Vous pouvez activer cette fonctionnalité au moyen du paramètre `core.autocrlf`.
268
+ Si vous avez une machine Windows, positionnez-le à `true`.
269
+ Git convertira les fins de ligne de LF en CRLF lorsque vous extrayerez votre code :
270
+
271
+ $ git config --global core.autocrlf true
272
+
273
+ Si vous utilisez un système Linux ou Mac qui utilise les fins de ligne LF, vous ne souhaitez sûrement pas que Git les convertisse automatiquement lorsque vous extrayez des fichiers.
274
+ Cependant, si un fichier contenant des CRLF est accidentellement introduit en version, vous souhaitez que Git le corrige .
275
+ Vous pouvez indiquer à Git de convertir CRLF en LF lors de la validation mais pas dans l'autre sens en fixant `core.autocrlf` à `input` :
276
+
277
+ $ git config --global core.autocrlf input
278
+
279
+ Ce réglage devrait donner des fins de ligne en CRLF lors d'extraction sous Windows mais en LF sous Mac et Linux et dans le dépôt.
280
+
281
+ Si vous êtes un programmeur Windows gérant un projet spécifique à Windows, vous pouvez désactiver cette fonctionnalité et forcer l'enregistrement des « retour chariot » dans le dépôt en réglant la valeur du paramètre à `false` :
282
+
283
+ $ git config --global core.autocrlf false
284
+
285
+ #### core.whitespace ####
286
+
287
+ Git est paramétré par défaut pour détecter et corriger certains problèmes de blancs.
288
+ Il peut rechercher quatre problèmes de blancs de base.
289
+ La correction de deux problèmes est activée par défaut et peut être désactivée et celle des deux autres n'est pas activée par défaut mais peut être activée.
290
+
291
+ Les deux activées par défaut sont `trailing-space` qui détecte les espaces en fin de ligne et `space-before-tab` qui recherche les espaces avant les tabulations au début d'une ligne.
292
+
293
+ Les deux autres qui sont désactivées par défaut mais peuvent être activées sont `indent-with-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 fin de ligne sont acceptés.
294
+
295
+ Vous pouvez indiquer à Git quelle correction vous voulez activer en fixant `core.whitespace` avec les valeurs que vous voulez ou non, séparées par des virgules.
296
+ Vous pouvez désactiver des réglages en les éliminant de la chaîne de paramétrage ou en les préfixant avec un `-`.
297
+ Par exemple, si vous souhaitez activer tout sauf `cr-at-eol`, vous pouvez lancer ceci :
298
+
299
+ $ git config --global core.whitespace \
300
+ trailing-space,space-before-tab,indent-with-non-tab
301
+
302
+ Git va détecter ces problèmes quand vous lancez une commande `git diff` et essayer de les coloriser pour vous permettre de les régler avant de valider.
303
+ Il utilisera aussi ces paramètres pour vous aider quand vous appliquerez des patchs avec `git apply`.
304
+ Quand vous appliquez des patchs, vous pouvez paramétrer Git pour qu'il vous avertisse s'il doit appliquer des patchs qui présentent les défauts de blancs :
305
+
306
+ $ git apply --whitespace=warn <patch>
307
+
308
+ Ou vous pouvez indiquer à Git d'essayer de corriger automatiquement le problème avant d'appliquer le patch :
309
+
310
+ $ git apply --whitespace=fix <patch>
311
+
312
+ Ces options s'appliquent aussi à `git rebase`.
313
+ Si vous avez validé avec des problèmes de blancs mais n'avez pas encore poussé en amont, vous pouvez lancer un `rebase` avec l'option `--whitespace=fix` pour faire corriger à Git les erreurs de blancs pendant qu'il réécrit les patchs.
314
+
315
+ ### Configuration du serveur ###
316
+
317
+ Il n'y a pas autant d'options de configuration de Git côté serveur, mais en voici quelques unes intéressantes dont il est utile de prendre note.
318
+
319
+ #### receive.fsckObjects ####
320
+
321
+ Par défaut, Git ne vérifie pas la cohérence entre les objets qu'on lui pousse.
322
+ Bien que Git puisse vérifier que chaque objet correspond bien à sa somme de contrôle et pointe vers des objets valides, il ne le fait pas par défaut sur chaque poussée.
323
+ C'est une opération relativement lourde qui peut énormément allonger les poussées selon la taille du dépôt ou de la poussée.
324
+ Si vous voulez que Git vérifie la cohérence des objets à chaque poussée, vous pouvez le forcer en fixant le paramètre `receive.fsckObjects` à true :
325
+
326
+ $ git config --system receive.fsckObjects true
327
+
328
+ Maintenant, Git va vérifier l'intégrité de votre dépôt avant que chaque poussée ne soit acceptée pour s'assurer que des clients défectueux n'introduisent pas des données corrompues.
329
+
330
+ #### receive.denyNonFastForwards ####
331
+
332
+ Si vous rebasez des *commits* que vous avez déjà poussés, 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.
333
+ C'est généralement une bonne politique, mais dans le cas d'un rebasage, vous pouvez décider que vous savez ce que vous faîtes et forcer la mise à jour de la branche distante en ajoutant l'option `-f` à votre commande.
334
+
335
+ Pour désactiver la possibilité de forcer la mise à jour des branches distantes autres qu'en avance rapide, réglez `receive.denyNonFastForwards` :
336
+
337
+ $ git config --system receive.denyNonFastForwards true
338
+
339
+ L'autre moyen d'obtenir ce résultat réside dans les crochets de réception côté serveur, qui seront abordés en seconde partie.
340
+ Cette approche vous permet de faire des choses plus complexes tel qu'interdire les modifications sans avance rapide à un certain groupe d'utilisateurs.
341
+
342
+ #### receive.denyDeletes ####
343
+
344
+ Un contournement possible de la politique `denyNonFastForwards` consiste à effacer la branche puis à la repousser avec ses nouvelles références.
345
+ Dans les versions les plus récentes de Git (à partir de la version 1.6.1), vous pouvez régler `receive.denyDeletes` à true :
346
+
347
+ $ git config --system receive.denyDeletes true
348
+
349
+ Cela interdit totalement l'effacement de branche et d'étiquette.
350
+ Aucun utilisateur n'en a le droit.
351
+ Pour pouvoir effacer des branches distantes, vous devez effacer manuellement les fichiers de référence sur le serveur.
352
+ Il existe aussi des moyens plus intéressants de gérer cette politique utilisateur par utilisateur au moyen des listes de contrôle d'accès, point qui sera abordé à la fin de ce chapitre.
353
+
354
+ ## Attributs Git ##
355
+
356
+ Certains de ces réglages peuvent aussi s'appliquer sur un chemin, de telle sorte que Git ne les applique que sur un sous-répertoire ou un sous-ensemble de fichiers.
357
+ Ces réglages par chemin sont appelés attributs Git et sont définis soit dans un fichier `.gitattributes` dans un répertoire (normalement la racine du projet), soit dans un fichier `.git/info/attributes` si vous ne souhaitez pas que le fichier de description des attributs fasse partie du projet.
358
+
359
+ Les attributs permettent de spécifier des stratégies de fusion différentes pour certains fichiers ou répertoires dans votre projet, d'indiquer à Git la manière de calculer les différences pour certains fichiers non-texte, ou de faire filtrer à Git le contenu avant qu'il ne soit validé ou extrait.
360
+ Dans ce chapitre, nous traiterons certains attributs applicables aux chemins et détaillerons quelques exemples de leur utilisation en pratique.
361
+
362
+ ### Fichiers binaires ###
363
+
364
+ Un des trucs malins permis par les attributs Git est d'indiquer à Git quels fichiers sont binaires (dans les cas où il ne pourrait pas le deviner par lui-même) et de lui donner les instructions spécifiques pour les traiter.
365
+ Par exemple, certains fichiers peuvent être générés par machine et impossible à traiter par diff, tandis que pour certains autres fichiers binaires, les différences peuvent être calculées.
366
+ Nous détaillerons comment indiquer à Git l'un et l'autre.
367
+
368
+ #### Identification des fichiers binaires ####
369
+
370
+ Certains fichiers ressemblent à des fichiers texte mais doivent en tout état de cause être traités comme des fichiers binaires.
371
+ Par exemple, les projets Xcode sous Mac contiennent un fichier finissant en `.pbxproj`, qui est en fait un jeu de données JSON (format de données en texte JavaScript) enregistré par l'application EDI pour y sauver les réglages entre autres de compilation.
372
+ Bien que ce soit techniquement un fichier texte en ASCII, il n'y a aucun intérêt à le gérer comme tel parce que c'est en fait une mini base de données.
373
+ Il est impossible de fusionner les contenus si deux utilisateurs le modifient et les calculs de différence par défaut sont inutiles.
374
+ Ce fichier n'est destiné qu'à être manipulé par un programme.
375
+ En résumé, ce fichier doit être considéré comme un fichier binaire opaque.
376
+
377
+ Pour indiquer à Git de traiter tous les fichiers `pbxproj` comme binaires, ajoutez la ligne suivante à votre fichier `.gitattributes` :
378
+
379
+ *.pbxproj -crlf -diff
380
+
381
+ À présent, Git n'essaiera pas de convertir ou de corriger les problèmes des CRLF, ni de calculer ou d'afficher les différences pour ces fichiers quand vous lancez `git show` ou `git diff` sur votre projet.
382
+ Dans la branche 1.6 de Git, vous pouvez aussi utiliser une macro fournie qui signifie `-crlf -diff` :
383
+
384
+ *.pbxproj binary
385
+
386
+ #### Comparaison de fichiers binaires ####
387
+
388
+ Dans Git, vous pouvez utiliser la fonctionnalité des attributs pour comparer efficacement les fichiers binaires.
389
+ Pour ce faire, indiquez à Git comment convertir vos données binaires en format texte qui peut être comparé via un diff normal.
390
+ Mais le question revient alors à savoir comment convertir les données binaires en texte.
391
+ La meilleure solution consiste à trouver un outil qui réalise pour vous la conversion des données binaires en représentation textuelle (imaginez par exemple comment convertir un fichier audio en texte).
392
+ Si c'est impossible et qur vous ne parvenez pas à obtenir une réprésentation du contenu sous forme de texte, il reste relativement facile d'obtenir une description dans un format humainement lisible de ce contenu.
393
+ Les métadonnées ne vous donneront pas une représentation complète du contenu du fichier, mais c'est en tout cas mieux que rien.
394
+
395
+ Nous allons utiliser les deux méthodes précédentes pour obtenir des comparaisons de formats binaires largement utilisés.
396
+
397
+ Note : il existe de nombreux types de formats binaires avec du contenu textuel pour lesquels il est difficile de trouver une convertisseur vers du texte.
398
+ Dans ces cas, il reste toujours possible d'extraire le texte au moyen du programme `strings`.
399
+ Certains de ces fichiers peuvent aussi utiliser une encodage spécifique du texte, comme UTF-16, et `strings` ne trouvera alors rien de probant.
400
+ Les résultats sont très variables.
401
+ Dans tous les cas, `strings` est disponible sur la plupart des systèmes Mac et Linux, et constitue une bonne option pour un premier essai.
402
+
403
+ ##### Fichiers MS Word #####
404
+
405
+ Premièrement, nous utiliserons cette technique pour résoudre un des problèmes les plus ennuyeux de l'humanité : gérer en contrôle de version les documents Word.
406
+ Tout le monde convient que Word est l'éditeur de texte le plus horrible qui existe, mais bizarrement, tout le monde persiste à l'utiliser.
407
+ Si vous voulez gérer en version des documents Word, vous pouvez les coller dans un dépôt Git et les valider de temps à autre.
408
+ Mais qu'est-ce que ça vous apporte ?
409
+ Si vous lancez `git diff` normalement, vous verrez quelque chose comme :
410
+
411
+ $ git diff
412
+ diff --git a/chapter1.doc b/chapter1.doc
413
+ index 88839c4..4afcb7c 100644
414
+ Binary files a/chapter1.doc and b/chapter1.doc differ
415
+
416
+ Vous ne pouvez pas comparer directement les versions à moins de les extraire et de les parcourir manuellement.
417
+ En fait, vous pouvez faire la même chose plutôt bien en utilisant les attributs Git.
418
+ Ajoutez la ligne suivante dans votre fichier `.gitattributes` :
419
+
420
+ *.doc diff=word
421
+
422
+ Cette ligne indique à Git que tout fichier correspondant au patron (.doc) doit utiliser le filtre `word` pour visualiser le diff des modifications.
423
+ Qu'est-ce que le filtre « word » ?
424
+ Nous devons le définir.
425
+ Vous allez indiquer à Git d'utiliser le programme `catdoc` qui a été écrit spécifiquement pour extraire le texte d'un document MS Word.
426
+ Vous pouvez l'obtenir depuis `http://www.wagner.pp.ru/~vitus/software/catdoc`.
427
+
428
+ $ git config diff.word.textconv catdoc
429
+
430
+ Cette commande ajoute à votre fichier `.git/config` une section qui ressemble à ceci :
431
+
432
+ [diff "word"]
433
+ textconv = catdoc
434
+
435
+ À présent, Git sait que s'il essaie de faire un diff entre deux instantanés et qu'un des fichiers finit en `.doc`, il devrait faire passer ces fichiers par le filtre `word` défini comme le programme `catdoc`.
436
+ Cette méthode fait effectivement des jolies versions texte de vos fichiers Word avant d'essayer de les comparer.
437
+
438
+ Voici un exemple.
439
+ J'ai mis le chapitre 1 de ce livre dans Git, ajouté du texte à un paragraphe et sauvegardé le document.
440
+ Puis, j'ai lancé `git diff` pour visualiser ce qui a changé :
441
+
442
+ $ git diff
443
+ diff --git a/chapter1.doc b/chapter1.doc
444
+ index c1c8a0a..b93c9e4 100644
445
+ --- a/chapter1.doc
446
+ +++ b/chapter1.doc
447
+ @@ -128,7 +128,7 @@ and data size)
448
+ Since its birth in 2005, Git has evolved and matured to be easy to use
449
+ and yet retain these initial qualities. It’s incredibly fast, it’s
450
+ very efficient with large projects, and it has an incredible branching
451
+ -system for non-linear development.
452
+ +system for non-linear development (See Chapter 3).
453
+
454
+ Git m'indique succinctement que j'ai ajouté la chaîne « (see Chapter 3) », ce qui est correct.
455
+
456
+ ##### Fichiers OpenDocument texte #####
457
+
458
+ Une approche identique à celle des fichiers MS Word (`*.doc`) peut être appliquée aux fichiers texte OpenDocument (`*.odt`) créés par OpenOffice.org ou LibreOffice.
459
+
460
+ Ajoutez la ligne suivante à la fin de votre fichier `.gitattributes` :
461
+
462
+ *.odt diff=odt
463
+
464
+ À présent, renseignez le filtre de différence `odt` dans `.git/config` :
465
+
466
+ [diff "odt"]
467
+ binary = true
468
+ textconv = /usr/local/bin/odt-to-txt
469
+
470
+ Les fichiers OpenDocument sont en fait des répertoires compressés par zip, contenant de nombreux fichiers (le contenu en format XML, les feuilles de style, les images, etc.).
471
+ Nous allons devoir écrire un script capable d'extraire le contenu et de l'afficher comme simple texte.
472
+ Créez un fichier `/usr/local/bin/odt-to-txt` (vous êtes libre de le placer dans un répertoire différent) contenant le texte suivant :
473
+
474
+ #! /usr/bin/env perl
475
+ # Convertisseur simpliste OpenDocument Text (.odt) vers texte
476
+ # Author: Philipp Kempgen
477
+
478
+ if (! defined($ARGV[0])) {
479
+ print STDERR "Pas de fichier fourni!\n";
480
+ print STDERR "Usage: $0 [nom du fichier]\n";
481
+ exit 1;
482
+ }
483
+
484
+ my $content = '';
485
+ open my $fh, '-|', 'unzip', '-qq', '-p', $ARGV[0], 'content.xml' or die $!;
486
+ {
487
+ local $/ = undef; # slurp mode
488
+ $content = <$fh>;
489
+ }
490
+ close $fh;
491
+ $_ = $content;
492
+ s/<text:span\b[^>]*>//g; # éliminer spans
493
+ s/<text:h\b[^>]*>/\n\n***** /g; # en-têtes
494
+ s/<text:list-item\b[^>]*>\s*<text:p\b[^>]*>/\n -- /g; # items de liste
495
+ s/<text:list\b[^>]*>/\n\n/g; # listes
496
+ s/<text:p\b[^>]*>/\n /g; # paragraphes
497
+ s/<[^>]+>//g; # nettoyer les balises XML
498
+ s/\n{2,}/\n\n/g; # nettoyer les lignes vides consécutives
499
+ s/\A\n+//; # nettoyer les lignes vides d'en-tête
500
+ print "\n", $_, "\n\n";
501
+
502
+ Puis rendez-le exécutable :
503
+
504
+ chmod +x /usr/local/bin/odt-to-txt
505
+
506
+ Maintenant, `git diff` est capable de vous indiquer ce qui a changé dans les fichiers `odt`.
507
+
508
+
509
+ ##### Fichiers image #####
510
+
511
+ Un autre problème intéressant concerne la comparaison de fichiers d'images.
512
+ Une méthode consiste à faire passer les fichiers PNG à travers un filtre qui extrait les données EXIF, les méta-données enregistrées avec la plupart des formats d'image.
513
+ Si vous téléchargez et installez le programme `exiftool`, vous pouvez l'utiliser pour convertir vos images en texte de méta-données de manière que le diff puisse au moins montrer une représentation textuelle des modifications pratiquées :
514
+
515
+ $ echo '*.png diff=exif' >> .gitattributes
516
+ $ git config diff.exif.textconv exiftool
517
+
518
+ Si vous remplacez une image dans votre projet et lancez `git diff`, vous verrez ceci :
519
+
520
+ diff --git a/image.png b/image.png
521
+ index 88839c4..4afcb7c 100644
522
+ --- a/image.png
523
+ +++ b/image.png
524
+ @@ -1,12 +1,12 @@
525
+ ExifTool Version Number : 7.74
526
+ -File Size : 70 kB
527
+ -File Modification Date/Time : 2009:04:17 10:12:35-07:00
528
+ +File Size : 94 kB
529
+ +File Modification Date/Time : 2009:04:21 07:02:43-07:00
530
+ File Type : PNG
531
+ MIME Type : image/png
532
+ -Image Width : 1058
533
+ -Image Height : 889
534
+ +Image Width : 1056
535
+ +Image Height : 827
536
+ Bit Depth : 8
537
+ Color Type : RGB with Alpha
538
+
539
+ Vous pouvez réaliser rapidement que la taille du fichier et les dimensions des images ont changé.
540
+
541
+ ### Expansion des mots-clés ###
542
+
543
+ L'expansion de mots-clés dans le style de CVS ou de SVN est souvent une fonctionnalité demandée par les développeurs qui y sont habitués.
544
+ Le problème principal de ce système avec Git est que vous ne pouvez pas modifier un fichier avec l'information concernant le *commit* après la validation parce que Git calcule justement la somme de contrôle sur son contenu.
545
+ Cependant, vous pouvez injecter des informations textuelles dans un fichier au moment où il est extrait et les retirer avant qu'il ne soit ajouté à un *commit*.
546
+ Les attributs Git vous fournissent deux manières de le faire.
547
+
548
+ Premièrement, vous pouvez injecter automatiquement la somme de contrôle SHA-1 d'un blob dans un champ `$Id$` d'un fichier.
549
+ Si vous positionnez cet attribut pour un fichier ou un ensemble de fichiers, la prochaine fois que vous extrairez cette branche, Git remplacera chaque champ avec le SHA-1 du blob.
550
+ Il est à noter que ce n'est pas le SHA du *commit* mais celui du blob lui-même :
551
+
552
+ $ echo '*.txt ident' >> .gitattributes
553
+ $ echo '$Id$' > test.txt
554
+
555
+ À la prochaine extraction de ce fichier, Git injecte le SHA du blob :
556
+
557
+ $ rm test.txt
558
+ $ git checkout -- test.txt
559
+ $ cat test.txt
560
+ $Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $
561
+
562
+ Néanmoins, ce résultat n'a que peu d'intérêt.
563
+ Si vous avez utilisé la substitution avec CVS ou Subversion, il est possible d'inclure la date.
564
+ Le code SHA n'est pas des plus utiles car il ressemble à une valeur aléatoire et ne vous permet pas de distinguer si tel SHA est plus récent ou plus ancien que tel autre.
565
+
566
+ Il apparaît que vous pouvez écrire vos propres filtres pour réaliser des substitutions dans les fichiers lors des validations/extractions.
567
+ Ces filtres s'appellent « *clean* » et « *smudge* ».
568
+ Dans le fichier `.gitattributes`, vous pouvez indiquer un filtre pour des chemins particuliers puis créer des scripts qui traiteront ces fichiers avant qu'ils soient extraits (« *smudge* », voir figure 7-2) et juste avant qu'ils soient validés (« *clean* », voir figure 7-2).
569
+ Ces filtres peuvent servir à faire toutes sortes de choses attrayantes.
570
+
571
+ Insert 18333fig0702.png
572
+ Figure 7-2. Le filtre « *smudge* » est lancé lors d'une extraction.
573
+
574
+ Insert 18333fig0703.png
575
+ Figure 7-3. Le filtre « *clean* » est lancé lorsque les fichiers sont indexés.
576
+
577
+ Le message de validation d'origine pour cette fonctionnalité donne un exemple simple permettant de passer tout votre code C par le programme `indent` avant de valider.
578
+ Vous pouvez le faire en réglant l'attribut `filter` dans votre fichier `.gitattributes` pour filtrer les fichiers `*.c` avec le filtre « indent » :
579
+
580
+ *.c filter=indent
581
+
582
+ Ensuite, indiquez à Git ce que le filtre « indent » fait sur *smudge* et *clean* :
583
+
584
+ $ git config --global filter.indent.clean indent
585
+ $ git config --global filter.indent.smudge cat
586
+
587
+ Dans ce cas, quand vous validez des fichiers 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.
588
+ Le programme `cat` ne fait rien : il se contente de régurgiter les données telles qu'il les a lues.
589
+ Cette combinaison filtre effectivement tous les fichiers de code source C par `indent` avant leur validation.
590
+
591
+ Un autre exemple intéressant fournit l'expansion du mot-clé `$Date$` dans le style RCS.
592
+ Pour le réaliser correctement, vous avez besoin d'un petit script qui prend un nom de fichier, calcule la date de la dernière validation pour le projet et l'insère dans le fichier.
593
+ Voici un petit script Ruby qui le fait :
594
+
595
+ #! /usr/bin/env ruby
596
+ data = STDIN.read
597
+ last_date = `git log --pretty=format:"%ad" -1`
598
+ puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')
599
+
600
+ Tout ce que le script fait, c'est récupérer la date de la dernière validation à partir de la commande `git log`, la coller dans toutes les chaînes `$Date$` qu'il trouve et réécrire le résultat.
601
+ Ce devrait être simple dans n'importe quel langage avec lequel vous êtes à l'aise.
602
+ Appelez ce fichier `expand_date` et placez-le dans votre chemin.
603
+ À présent, il faut paramétrer un filtre dans Git (appelons le `dater`) et lui indiquer d'utiliser le filtre `expand_date` en tant que *smudge* sur les fichiers à extraire.
604
+ Nous utiliserons une expression Perl pour nettoyer lors d'une validation :
605
+
606
+ $ git config filter.dater.smudge expand_date
607
+ $ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'
608
+
609
+ Cette commande Perl extrait tout ce qu'elle trouve dans une chaîne `$Date$` et la réinitialise.
610
+ Le filtre prêt, on peut le tester en écrivant le mot-clé `$Date$` dans un fichier, puis en créant un attribut Git pour ce fichier qui fait référence au nouveau filtre :
611
+
612
+ $ echo '# $Date$' > date_test.txt
613
+ $ echo 'date*.txt filter=dater' >> .gitattributes
614
+
615
+ Si vous validez ces modifications et extrayez le fichier à nouveau, vous remarquez le mot-clé correctement substitué :
616
+
617
+ $ git add date_test.txt .gitattributes
618
+ $ git commit -m "Testing date expansion in Git"
619
+ $ rm date_test.txt
620
+ $ git checkout date_test.txt
621
+ $ cat date_test.txt
622
+ # $Date: Tue Apr 21 07:26:52 2009 -0700$
623
+
624
+ Vous pouvez voir à quel point cette technique peut être puissante pour des applications personnalisées.
625
+ Il faut rester néanmoins vigilant car le fichier `.gitattributes` est validé et inclus dans le projet tandis que le gestionnaire (ici, `dater`) ne l'est pas.
626
+ Du coup, ça ne marchera pas partout.
627
+ Lorsque vous créez ces filtres, ils devraient pouvoir avoir un mode dégradé qui n'empêche pas le projet de fonctionner.
628
+
629
+ ### Export d'un dépôt ###
630
+
631
+ Les données d'attribut Git permettent aussi de faire des choses intéressantes quand vous exportez une archive du projet.
632
+
633
+ #### export-ignore ####
634
+
635
+ Vous pouvez dire à Git de ne pas exporter certains fichiers ou répertoires lors de la génération d'archive.
636
+ S'il y a un sous-répertoire ou un fichier que vous ne souhaitez pas inclure dans le fichier archive mais que vous souhaitez extraire dans votre projet, vous pouvez indiquer ce fichier via l'attribut `export-ignore`.
637
+
638
+ Par exemple, disons que vous avez des fichiers de test dans le sous-répertoire `test/` et que ce n'est pas raisonnable de les inclure dans l'archive d'export de votre projet.
639
+ Vous pouvez ajouter la ligne suivante dans votre fichier d'attribut Git :
640
+
641
+ test/ export-ignore
642
+
643
+ À présent, quand vous lancez `git archive` pour créer une archive `tar` de votre projet, ce répertoire ne sera plus inclus dans l'archive.
644
+
645
+ #### export-subst ####
646
+
647
+ Une autre chose à faire pour vos archives est une simple substitution de mots-clés.
648
+ Git vous permet de placer la chaîne `$Format:$` dans n'importe quel fichier avec n'importe quel code de format du type `--pretty=format` que vous avez pu voir au chapitre 2.
649
+ Par exemple, si vous voulez inclure un fichier appelé `LAST_COMMIT` dans votre projet et y injecter automatiquement la date de dernière validation lorsque `git archive` est lancé, vous pouvez créer un fichier comme ceci :
650
+
651
+ $ echo 'Last commit date: $Format:%cd$' > LAST_COMMIT
652
+ $ echo "LAST_COMMIT export-subst" >> .gitattributes
653
+ $ git add LAST_COMMIT .gitattributes
654
+ $ git commit -am 'adding LAST_COMMIT file for archives'
655
+
656
+ Quand vous lancez `git archive`, le contenu de ce fichier inclus dans l'archive ressemblera à ceci :
657
+
658
+ $ cat LAST_COMMIT
659
+ Last commit date: $Format:Tue Apr 21 08:38:48 2009 -0700$
660
+
661
+ ### Stratégies de fusion ###
662
+
663
+ Vous pouvez aussi utiliser les attributs Git pour indiquer à Git d'utiliser des stratégies de fusion différenciées pour des fichiers spécifiques dans votre projet.
664
+ Une option très utile est d'indiquer à Git de ne pas essayer de fusionner des fichiers spécifiques quand ils rencontrent des conflits mais plutôt d'utiliser prioritairement votre version du fichier.
665
+
666
+ C'est très utile si une branche de votre projet a divergé ou s'est spécialisée, mais que vous souhaitez pouvoir fusionner les modifications qu'elle porte et vous voulez ignorer certains fichiers.
667
+ Supposons que vous avez un fichier de paramètres de base de données appelé `database.xml` différent sur deux branches et vous voulez les fusionner sans corrompre le fichier de base de données.
668
+ Vous pouvez déclarer un attribut comme ceci :
669
+
670
+ database.xml merge=ours
671
+
672
+ Si vous fusionnez dans une autre branche, plutôt que de rencontrer des conflits de fusion avec le fichier database.xml, vous verrez quelque chose comme :
673
+
674
+ $ git merge topic
675
+ Auto-merging database.xml
676
+ Merge made by recursive.
677
+
678
+ Dans ce cas, `database.xml` reste dans l'état d'origine, quoi qu'il arrive.
679
+
680
+ ## Crochets Git ##
681
+
682
+ Comme de nombreux autres systèmes de gestion de version, Git dispose d'un moyen de lancer des scripts personnalisés quand certaines actions importantes ont lieu.
683
+ Il y a deux groupes de crochets : ceux côté client et ceux côté serveur.
684
+ Les crochets côté client concernent les opérations de client telles que la validation et la fusion.
685
+ Les crochets côté serveur concernent les opérations de serveur Git telles que la réception de *commits*.
686
+ Vous pouvez utiliser ces crochets pour toutes sortes de raisons dont nous allons détailler quelques unes.
687
+
688
+ ### Installation d'un crochet ###
689
+
690
+ Les crochets sont tous stockés dans le sous-répertoire `hooks` du répertoire Git.
691
+ Dans la plupart des projets, c'est `.git/hooks`.
692
+ Par défaut, Git popule ce répertoire avec quelques scripts d'exemple déjà utiles par eux-mêmes ; mais ils servent aussi de documentation sur les paramètres de chaque script.
693
+ Tous les exemples sont des scripts shell avec un peu de Perl mais n'importe quel script exécutable nommé correctement fonctionnera. Vous pouvez les écrire en Ruby ou Python ou ce que vous voudrez.
694
+ Pour les versions de Git postérieures à 1.6, ces fichiers crochet d'exemple se terminent en `.sample` et il faudra les renommer.
695
+ Pour les versions de Git antérieures à 1.6, les fichiers d'exemple sont nommés correctement mais ne sont pas exécutables.
696
+
697
+ Pour activer un script de crochet, placez un fichier dans le sous-répertoire `hook` de votre répertoire Git, nommé correctement et exécutable.
698
+ À partir de ce moment, il devrait être appelé.
699
+ Abordons donc les noms de fichiers de crochet les plus importants.
700
+
701
+ ### Crochets côté client ###
702
+
703
+ Il y a de nombreux crochets côté client.
704
+ Ce chapitre les classe entre crochets de traitement de validation, scripts de traitement par e-mail et le reste des scripts côté client.
705
+
706
+ #### Crochets de traitement de validation ####
707
+
708
+ Les quatre premiers crochets ont trait au processus de validation.
709
+ Le crochet `pre-commit` est lancé en premier, avant même que vous ne saisissiez le message de validation.
710
+ Il est utilisé pour inspecter l'instantané qui est sur le point d'être validé, pour vérifier si vous avez oublié quelque chose, pour s'assurer que les tests passent ou pour examiner ce que vous souhaitez inspecter dans le code.
711
+ Un code de sortie non nul de ce crochet annule la validation, bien que vous puissiez le contourner avec `git commit --no-verify`.
712
+ Vous pouvez réaliser des actions telles qu'une vérification de style (en utilisant lint ou un équivalent), d'absence de blancs en fin de ligne (le crochet par défaut fait exactement cela) ou de documentation des nouvelles méthodes.
713
+
714
+ Le crochet `prepare-commit-msg` est appelé avant que l'éditeur de message de validation ne soit lancé après que le message par défaut a été créé.
715
+ Il vous permet d'éditer le message par défaut avant que l'auteur ne le voit.
716
+ Ce crochet accepte quelques options : le chemin du fichier qui contient le message de validation actuel, le type de validation et le SHA-1 du *commit* si c'est un *commit* amendé.
717
+ Ce crochet ne sert généralement à rien pour les validations normales.
718
+ Par contre, il est utile pour les validations où le message par défaut est généré, tel que les modèles de message de validation, les validations de fusion, les *commits* écrasés ou amendés.
719
+ Vous pouvez l'utiliser en conjonction avec un modèle de messages pour insérer de l'information par programme.
720
+
721
+ Le crochet `commit-msg` accepte un paramètre qui est encore le chemin du fichier temporaire qui contient le message de validation actuel.
722
+ Si ce script rend un code de sortie non nul, Git abandonne le processus de validation, ce qui vous permet de vérifier l'état de votre projet ou du message de validation avant de laisser passer un *commit*.
723
+ Dans la dernière section de ce chapitre, l'utilisation de ce crochet permettra de vérifier que le message de validation est conforme à un format obligatoire.
724
+
725
+ Après l'exécution du processus complet de validation, le crochet `post-commit` est appelé.
726
+ Il n'accepte aucun argument mais vous pouvez facilement accéder au dernier *commit* grâce à `git log -1 HEAD`.
727
+ Généralement, ce script sert à réaliser des notifications ou des choses similaires.
728
+
729
+ Les scripts de gestion de validation côté client peuvent être utilisés pour n'importe quelle méthode de travail.
730
+ Ils sont souvent utilisés pour mettre en œuvre certaines politiques, bien qu'il faille noter que ces scripts ne sont pas transférés lors d'un clonage.
731
+ Vous pouvez faire appliquer les politiques de gestion au niveau serveur pour rejeter les poussées de *commits* qui ne sont pas conformes à certaines règles, mais il reste complètement du ressort du développeur de les utiliser côté client.
732
+ Ce sont des scripts destinés à aider les développeurs et ils doivent être mis en place et maintenus par ces derniers qui peuvent tout aussi bien les outrepasser ou les modifier à tout moment.
733
+
734
+ #### Crochets de gestion e-mail ####
735
+
736
+ Vous pouvez régler trois crochets côté client pour la gestion à base d'e-mail.
737
+ Ils sont tous invoqués par la commande `git am`, donc si vous n'êtes pas habitués à utiliser cette commande dans votre mode de gestion, vous pouvez simplement passer la prochaine section.
738
+ Si vous acceptez des patchs préparés par `git format-patch` par e-mail, alors certains de ces crochets peuvent vous être très utiles.
739
+
740
+ Le premier crochet lancé est `applypatch-msg`.
741
+ Il accepte un seul argument : le nom du fichier temporaire qui contient le message de validation proposé.
742
+ Git abandonne le patch si ce script sort avec un code non nul.
743
+ Vous pouvez l'utiliser pour vérifier que la message de validation est correctement formaté ou pour normaliser le message en l'éditant sur place par script.
744
+
745
+ Le crochet lancé ensuite lors de l'application de patchs via `git am` s'appelle `pre-applypatch`.
746
+ Il n'accepte aucun argument et est lancé après que le patch a été appliqué, ce qui vous permet d'inspecter l'instantané avant de réaliser la validation.
747
+ Vous pouvez lancer des tests ou inspecter l'arborescence active avec ce script.
748
+ S'il 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.
749
+
750
+ Le dernier crochet lancé pendant l'opération `git am` s'appelle `post-applypatch`.
751
+ Vous pouvez l'utiliser pour notifier un groupe ou l'auteur du patch que vous venez de l'appliquer.
752
+ Vous ne pouvez plus arrêter le processus de validation avec ce script.
753
+
754
+ #### Autres crochets côté client ####
755
+
756
+ Le crochet `pre-rebase` est invoqué avant que vous ne rebasiez et peut interrompre le processus s'il sort avec un code d'erreur non nul.
757
+ Vous pouvez utiliser ce crochet pour empêcher de rebaser tout *commit* qui a déjà été poussé.
758
+ C'est ce que fait le crochet d'exemple `pre-rebase` que Git installe, même s'il considère que la branche cible de publication s'appelle `next`.
759
+ Il est très probable que vous ayez à changer ce nom pour celui que vous utilisez réellement en branche publique stable.
760
+
761
+ Après avoir effectué avec succès un `git checkout`, la crochet `post-chechout` est lancé.
762
+ Vous pouvez l'utiliser pour paramétrer correctement votre environnement projet dans votre copie de travail.
763
+ Cela peut signifier y déplacer des gros fichiers binaires que vous ne souhaitez pas voir en gestion de source, générer automatiquement la documentation ou quelque chose dans le genre.
764
+
765
+ Enfin, le crochet `post-merge` s'exécute à la suite d'une commande `merge` réussie.
766
+ Vous pouvez l'utiliser pour restaurer certaines données non gérées par Git dans le copie de travail telles que les informations de permission.
767
+ Ce crochet permet même de valider la présence de fichiers externes au contrôle de Git que vous souhaitez voir recopiés lorsque la copie de travail change.
768
+
769
+ ### Crochets côté serveur ###
770
+
771
+ En complément des crochets côté client, vous pouvez utiliser comme administrateur système quelques crochets côté serveur pour appliquer quasiment toutes les règles de votre projet.
772
+ Ces scripts s'exécutent avant et après chaque poussée sur le serveur.
773
+ Les crochets `pre` peuvent rendre un code d'erreur non nul à tout moment pour rejeter la poussée et afficher un message d'erreur au client.
774
+ Vous pouvez mettre en place des règles aussi complexes que nécessaire.
775
+
776
+ #### pre-receive et post-receive ####
777
+
778
+ Le premier script lancé lors de la gestion d'une poussée depuis un client est `pre-receive`.
779
+ Il accepte une liste de références lues sur *stdin*.
780
+ S'il sort avec un code d'erreur non nul, aucune n'est acceptée.
781
+ Vous pouvez utiliser ce crochet pour réaliser des tests tels que s'assurer que toutes les références mises à jour le sont en avance rapide ou pour s'assurer que l'utilisateur dispose bien des droits de création, poussée, destruction ou de lecture des mises à jour pour tous les fichiers qu'il cherche à mettre à jour dans cette poussée.
782
+
783
+ Le crochet `post-receive` est lancé après l'exécution complète du processus et peut être utilisé pour mettre à jour d'autres services ou pour notifier des utilisateurs.
784
+ Il accepte les mêmes données sur *stdin* que `pre-receive`.
785
+ Il peut par exemple envoyer un e-mail à une liste de diffusion, notifier un serveur d'intégration continue ou mettre à jour un système de suivi de tickets.
786
+ Il peut aussi analyser les messages de validation à la recherche d'ordres de mise à jour de l'état des tickets.
787
+ Ce script ne peut pas arrêter le processus de poussée mais le client n'est pas déconnecté tant qu'il n'a pas terminé.
788
+ Il faut donc être prudent à ne pas essayer de lui faire réaliser des actions qui peuvent durer longtemps.
789
+
790
+ #### update ####
791
+
792
+ Le script `update` est très similaire au script `pre-receive`, à la différence qu'il est lancé une fois par branche qui doit être modifiée lors de la poussée.
793
+ Si la poussée s'applique à plusieurs branches, `pre-receive` n'est lancé qu'une fois, tandis qu'`update` est lancé une fois par branche impactée.
794
+ Au lieu de lire à partir de stdin, ce script accepte trois arguments : le nom de la référence (branche), le SHA-1 du *commit* pointé par la référence avant la poussée et le SHA-1 que l'utilisateur est en train de pousser.
795
+ Si le script `update` se termine avec un code d'erreur non nul, seule la référence est rejetée.
796
+ Les autres références pourront être mises à jour.
797
+
798
+ ## Exemple de politique gérée par Git ##
799
+
800
+ Dans ce chapitre, nous allons utiliser ce que nous venons d'apprendre pour installer une gestion Git qui vérifie la présence d'un format personnalisé de message de validation, n'autorise que les poussées en avance rapide et autorise seulement certains utilisateurs à modifier certains sous-répertoires dans un projet.
801
+ Nous construirons des scripts client pour informer les développeurs que leurs poussées vont être rejetées et des scripts sur le serveur pour mettre effectivement en place ces règles.
802
+
803
+ J'ai utilisé Ruby pour les écrire, d'abord parce que c'est mon langage de script favori, ensuite parce que je pense que c'est le langage de script qui s'apparente le plus à du pseudo-code.
804
+ Ainsi, il devrait être simple de suivre grossièrement le code même sans connaître le langage Ruby.
805
+ Cependant, tout langage peut être utilisé.
806
+ Tous les scripts d'exemple distribués avec Git sont soit en Perl soit en Bash, ce qui donne de nombreux autres exemples de crochets dans ces langages.
807
+
808
+ ### Crochets côté serveur ###
809
+
810
+ Toutes les actions côté serveur seront contenues dans le fichier `update` dans le répertoire `hooks`.
811
+ Le fichier `update` s'exécute une fois par branche poussée et accepte comme paramètre la référence sur laquelle on pousse, l'ancienne révision de la branche et la nouvelle révision de la branche.
812
+ Vous pouvez aussi avoir accès à l'utilisateur qui pousse si la poussée est réalisée par SSH.
813
+ Si vous avez permis à tout le monde de se connecter avec un utilisateur unique (comme « git ») avec une authentification à clé publique, il vous faudra fournir à cet utilisateur une enveloppe de shell qui déterminera l'identité de l'utilisateur à partir de sa clé publique et positionnera une variable d'environnement spécifiant cette identité.
814
+ Ici, je considère que la variable d'environnement `$USER` indique l'utilisateur connecté, donc le script update commence par rassembler toutes les informations nécessaires :
815
+
816
+ #!/usr/bin/env ruby
817
+
818
+ $nomref = ARGV[0]
819
+ $anciennerev = ARGV[1]
820
+ $nouvellerev = ARGV[2]
821
+ $utilisateur = ENV['USER']
822
+
823
+ puts "Vérification des règles... \n(#{$nomref}) (#{$anciennerev[0,6]}) (#{$nouvellerev[0,6]})"
824
+
825
+ Et oui, j'utilise des variables globales.
826
+ C'est seulement pour simplifier la démonstration.
827
+
828
+ #### Application d'une politique de format du message de validation ####
829
+
830
+ Notre première tâche consiste à forcer que chaque message de validation adhère à un format particulier.
831
+ En guise d'objectif, obligeons chaque message à contenir une chaîne de caractère qui ressemble à « ref: 1234 » parce que nous souhaitons que chaque validation soit liée à une tâche de notre système de tickets.
832
+ Nous devons donc inspecter chaque *commit* poussé, vérifier la présence de la chaîne et sortir avec un code non-nul en cas d'absence pour rejeter la poussée.
833
+
834
+ Vous pouvez obtenir une liste des valeurs SHA-1 de tous les *commits* en cours de poussée en passant les valeurs `$nouvellerev` et `$anciennerev` à une commande de plomberie Git appelée `git-rev-list`.
835
+ C'est comme la commande `git log` mais elle n'affiche par défaut que les valeurs SHA-1, sans autre information.
836
+ Donc, pour obtenir une liste de tous les SHA des *commits* introduits entre un SHA de *commit* et un autre, il suffit de lancer quelque chose comme :
837
+
838
+ $ git rev-list 538c33..d14fc7
839
+ d14fc7c847ab946ec39590d87783c69b031bdfb7
840
+ 9f585da4401b0a3999e84113824d15245c13f0be
841
+ 234071a1be950e2a8d078e6141f5cd20c1e61ad3
842
+ dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a
843
+ 17716ec0f1ff5c77eff40b7fe912f9f6cfd0e475
844
+
845
+ Vous pouvez récupérer la sortie, boucler sur chacun de ces SHA de *commit*, en extraire le message et tester la conformité du message avec une structure au moyen d'une expression rationnelle.
846
+
847
+ Vous devez trouver comment extraire le message de validation à partir de chacun des *commits* à tester.
848
+ Pour accéder aux données brutes du *commit*, vous pouvez utiliser une autre commande de plomberie appelée `git cat-file`.
849
+ Nous traiterons en détail toutes ces commandes de plomberie au chapitre 9 mais pour l'instant, voici ce que cette commande affiche:
850
+
851
+ $ git cat-file commit ca82a6
852
+ tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
853
+ parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
854
+ author Scott Chacon <schacon@gmail.com> 1205815931 -0700
855
+ committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
856
+
857
+ changed the version number
858
+
859
+ Un moyen simple d'extraire le message de validation d'un *commit* à partir de son SHA-1 consiste à rechercher la première ligne vide et à sélectionner tout ce qui suit.
860
+ Cela peut être facilement réalisé avec la commande `sed` sur les systèmes Unix :
861
+
862
+ $ git cat-file commit ca82a6 | sed '1,/^$/d'
863
+ changed the version number
864
+
865
+ Vous pouvez utiliser cette ligne pour récupérer le message de validation de chaque *commit* en cours de poussée et sortir si quelque chose ne correspond à ce qui est attendu.
866
+ Pour sortir du script et rejeter la poussée, il faut sortir avec un code non nul.
867
+ La fonction complète ressemble à ceci :
868
+
869
+ $regex = /\[ref: (\d+)\]/
870
+
871
+ # vérification du format des messages de validation
872
+ def verif_format_message
873
+ revs_manquees = `git rev-list #{$anciennerev}..#{$nouvellerev}`.split("\n")
874
+ revs_manquees.each do |rev|
875
+ message = `git cat-file commit #{rev} | sed '1,/^$/d'`
876
+ if !$regex.match(message)
877
+ puts "[REGLE] Le message de validation n'est pas conforme"
878
+ exit 1
879
+ end
880
+ end
881
+ end
882
+ verif_format_message
883
+
884
+ Placer ceci dans un script `update` rejettera les mises à jour contenant des *commits* dont les messages ne suivent pas la règle.
885
+
886
+ #### Mise en place d'un système d'ACL par utilisateur ####
887
+
888
+ Supposons que vous souhaitiez ajouter un mécanisme à base de liste de contrôle d'accès (access control list : ACL) qui permette de spécifier quel utilisateur a le droit de pousser des modifications vers quelle partie du projet.
889
+ Certaines personnes ont un accès complet tandis que d'autres n'ont accès que pour mettre à jour certains sous-répertoires ou certains fichiers.
890
+ Pour faire appliquer ceci, nous allons écrire ces règles dans un fichier appelé `acl` situé dans le dépôt brut Git sur le serveur.
891
+ Le crochet `update` examinera ces règles, listera les fichiers impactés par la poussée et déterminera si l'utilisateur qui pousse a effectivement les droits nécessaires sur ces fichiers.
892
+
893
+ Écrivons en premier le fichier d'ACL.
894
+ Nous allons utiliser un format très proche de celui des ACL de CVS.
895
+ Le fichier est composé de lignes dont le premier champ est `avail` ou `unavail`, le second est une liste des utilisateurs concernés séparés par des virgules et le dernier champ indique le chemin pour lequel la règle s'applique (le champ vide indiquant une règle générale).
896
+ Tous les champs sont délimités par un caractère pipe « | ».
897
+
898
+ Dans notre cas, il y a quelques administrateurs, des auteurs de documentation avec un accès au répertoire `doc` et un développeur qui n'a accès qu'aux répertoires `lib` et `tests`.
899
+ Le fichier ACL ressemble donc à ceci :
900
+
901
+ avail|nickh,pjhyett,defunkt,tpw
902
+ avail|usinclair,cdickens,ebronte|doc
903
+ avail|schacon|lib
904
+ avail|schacon|tests
905
+
906
+ Le traitement consiste à lire le fichier dans une structure utilisable.
907
+ Dans notre cas, pour simplifier, nous ne traiterons que les directives `avail`.
908
+ Voici une fonction qui crée à partir du fichier un tableau associatif dont la clé est l'utilisateur et la valeur est une liste des chemins pour lesquels l'utilisateur a les droits en écriture :
909
+
910
+ def get_acl_access_data(nom_fichier_acl)
911
+ # lire le fichier ACL
912
+ fichier_acl = File.read(nom_fichier_acl).split("\n").reject { |ligne| ligne == '' }
913
+ acces = {}
914
+ fichier_acl.each do |ligne|
915
+ avail, utilisateurs, chemin = ligne.split('|')
916
+ next unless avail == 'avail'
917
+ utilisateurs.split(',').each do |utilisateur|
918
+ acces[utilisateur] ||= []
919
+ acces[utilisateur] << chemin
920
+ end
921
+ end
922
+ acces
923
+ end
924
+
925
+ Pour le fichier d'ACL décrit plus haut, le fonction `get_acl_access_data` retourne une structure de données qui ressemble à ceci :
926
+
927
+ {"defunkt"=>[nil],
928
+ "tpw"=>[nil],
929
+ "nickh"=>[nil],
930
+ "pjhyett"=>[nil],
931
+ "schacon"=>["lib", "tests"],
932
+ "cdickens"=>["doc"],
933
+ "usinclair"=>["doc"],
934
+ "ebronte"=>["doc"]}
935
+
936
+ En plus des permissions, il faut déterminer les chemins impactés par la poussée pour s'assurer que l'utilisateur a bien droit d'y toucher.
937
+
938
+ La liste des fichiers modifiés est assez simplement obtenue par la commande `git log` complétée par l'option `--name-only` mentionnée au chapitre 2.
939
+
940
+ $ git log -1 --name-only --pretty=format:'' 9f585d
941
+
942
+ README
943
+ lib/test.rb
944
+
945
+ Chaque fichier des *commits* doit être vérifié par rapport à la structure ACL retournée par la fonction `get_acl_access_data` pour déterminer si l'utilisateur a le droit de pousser tous ses *commits* :
946
+
947
+ # permission à certains utilisateurs de modifier certains sous-répertoires du projet
948
+ def verif_perms_repertoire
949
+ acces = get_acl_access_data('acl')
950
+
951
+ # verifier si quelqu'un chercher à pousser où il n'a pas le droit
952
+ nouveaux_commits = `git rev-list #{$anciennerev}..#{$nouvellerev}`.split("\n")
953
+ nouveaux_commits.each do |rev|
954
+ fichiers_modifies = `git log -1 --name-only --pretty=format:'' #{rev}`.split("\n")
955
+ fichiers_modifies.each do |chemin|
956
+ next if chemin.size == 0
957
+ acces_permis = false
958
+ acces[$utilisateur].each do |chemin_acces|
959
+ if !chemin_acces || # l'utilisateur a un accès complet
960
+ (chemin.index(chemin_acces) == 0) # acces à ce chemin
961
+ acces_permis = true
962
+ end
963
+ end
964
+ if !acces_permis
965
+ puts "[ACL] Vous n'avez pas le droit de pousser sur #{path}"
966
+ exit 1
967
+ end
968
+ end
969
+ end
970
+ end
971
+
972
+ verif_perms_repertoire
973
+
974
+ L'algorithme ci-dessus reste simple.
975
+ Pour chaque élément de la liste des nouveaux *commits* à pousser obtenue au moyen de `git rev-list`, on vérifie que l'utilisateur qui pousse a accès au chemin de chacun des fichiers modifiés.
976
+ L'expression `chemin.index(chemin_acces) == 0` est un Rubyisme qui n'est vrai que si `chemin` commence comme `chemin_acces`.
977
+ Ce script s'assure non pas qu'un `chemin` fait partie des chemins permis, mais que tous les chemins accédés font bien partie des chemins permis.
978
+
979
+ À présent, les utilisateurs ne peuvent plus pousser de *commits* comprenant un message incorrectement formaté ou des modifications à des fichiers hors de leur zone réservée.
980
+
981
+ #### Application des poussées en avance rapide ####
982
+
983
+ Il ne reste plus qu'à forcer les poussées en avance rapide uniquement.
984
+ À partir de la version 1.6, les paramètres `receive.denyDeletes` et `receive.denyNonFastForwards` règlent le problème.
985
+ Cependant, l'utilisation d'un crochet permet de fonctionner avec des versions antérieures de Git et même après modification, des permissions par utilisateur ou toute autre évolution.
986
+
987
+ L'algorithme consiste à vérifier s'il y a des *commits* accessibles depuis l'ancienne révision qui ne sont pas accessibles depuis la nouvelle.
988
+ S'il n'y en a aucun alors la poussée est effectivement en avance rapide.
989
+ Sinon, il faut le rejeter :
990
+
991
+ # Forcer les poussées qu'en avance rapide
992
+ def verif_avance_rapide
993
+ refs_manquees = `git rev-list #{$nouvellerev}..#{$anciennerev}`
994
+ nb_refs_manquees = refs_manquees.split("\n").size
995
+ if nb_refs_manquees > 0
996
+ puts "[REGLE] Poussée en avance rapide uniquement"
997
+ exit 1
998
+ end
999
+ end
1000
+
1001
+ verif_avance_rapide
1002
+
1003
+ Tout est en place.
1004
+ En lançant `chmod u+x .git/hooks/update`, `update` étant le fichier dans lequel tout le code précédent réside, puis en essayant de pousser une référence qui n'est pas en avance rapide, on obtient ceci :
1005
+
1006
+ $ git push -f origin master
1007
+ Counting objects: 5, done.
1008
+ Compressing objects: 100% (3/3), done.
1009
+ Writing objects: 100% (3/3), 323 bytes, done.
1010
+ Total 3 (delta 1), reused 0 (delta 0)
1011
+ Unpacking objects: 100% (3/3), done.
1012
+ Vérification des règles...
1013
+ (refs/heads/master) (8338c5) (c5b616)
1014
+ [REGLE] Poussée en avance rapide uniquement
1015
+ error: hooks/update exited with error code 1
1016
+ error: hook declined to update refs/heads/master
1017
+ To git@gitserver:project.git
1018
+ ! [remote rejected] master -> master (hook declined)
1019
+ error: failed to push some refs to 'git@gitserver:project.git'
1020
+
1021
+ Il y a plusieurs points à relever ici.
1022
+ Premièrement, une ligne indique l'endroit où le crochet est appelé.
1023
+
1024
+ Vérification des règles...
1025
+ (refs/heads/master) (8338c5) (c5b616)
1026
+
1027
+ Le script `update` affiche ces lignes sur stdout au tout début.
1028
+ Tout ce que le script écrit sur stdout sera transmis au client.
1029
+
1030
+ La ligne suivante à remarquer est le message d'erreur.
1031
+
1032
+ [REGLE] Poussée en avance rapide uniquement
1033
+ error: hooks/update exited with error code 1
1034
+ error: hook declined to update refs/heads/master
1035
+
1036
+ Le première ligne a été écrite par le script, les deux autres l'ont été par Git pour indiquer que le script `update` a rendu un code de sortie non nul, ce qui a causé l'échec de la poussée.
1037
+ Enfin, il y a ces lignes :
1038
+
1039
+ To git@gitserver:project.git
1040
+ ! [remote rejected] master -> master (hook declined)
1041
+ error: failed to push some refs to 'git@gitserver:project.git'
1042
+
1043
+ Il y a un message d'échec distant pour chaque référence que le crochet a rejetée et une indication que l'échec est dû spécifiquement à un échec du crochet.
1044
+
1045
+ Par ailleurs, si le marqueur `ref` n'est pas présent dans le message de validation, le message d'erreur spécifique est affiché :
1046
+
1047
+ [REGLE] Le message de validation n'est pas conforme
1048
+
1049
+ Ou si quelqu'un cherche à modifier un fichier auquel il n'a pas les droits d'accès lors d'une poussée, il verra quelque chose de similaire.
1050
+ Par exemple, si un auteur de documentation essaie de pousser un *commit* qui modifie quelque chose dans le répertoire `lib`, il verra :
1051
+
1052
+ [ACL] Vous n'avez pas le droit de pousser sur lib/test.rb
1053
+
1054
+ C'est tout.
1055
+ À partir de maintenant, tant que le script `update` est en place et exécutable, votre dépôt ne peut plus subir de poussées hors avancée rapide, n'accepte plus de messages sans format et vos utilisateurs sont bridés.
1056
+
1057
+ ### Crochets côté client ###
1058
+
1059
+ Le problème de cette approche, ce sont les plaintes des utilisateurs qui résulteront inévitablement des échecs de leurs poussées.
1060
+ Leur frustration et leur confusion devant le rejet à la dernière minute d'un travail minutieux est tout à fait compréhensible.
1061
+ De plus, la correction nécessitera une modification de leur historique, ce qui n'est pas une partie de plaisir.
1062
+
1063
+ Pour éviter ce scénario, il faut pouvoir fournir aux utilisateurs des crochets côté client qui leur permettront de vérifier que leurs validations seront effectivement acceptées par le serveur.
1064
+ Ainsi, ils pourront corriger les problèmes avant de valider et avant que ces difficultés ne deviennent des casse-têtes.
1065
+ Ces scripts n'étant pas diffusés lors du clonage du projet, il vous faudra les distribuer d'une autre manière, puis indiquer aux utilisateurs de les copier dans leur répertoire `.git/hooks` et de les rendre exécutables.
1066
+ Vous pouvez distribuer ces crochets au sein du projet ou dans un projet annexe mais il n'y a aucun moyen de les mettre en place automatiquement.
1067
+
1068
+ Premièrement, pour éviter le rejet du serveur au motif d'un mauvais format du message de validation, il faut vérifier celui-ci avant que chaque *commit* ne soit enregistré.
1069
+ Pour ce faire, utilisons le crochet `commit-msg`.
1070
+ En lisant le message à partir du fichier passé en premier argument et en le comparant au format attendu, on peut forcer Git à abandonner la validation en cas d'absence de correspondance :
1071
+
1072
+ #!/usr/bin/env ruby
1073
+ fichier_message = ARGV[0]
1074
+ message = File.read(fichier_message)
1075
+
1076
+ $regex = /\[ref: (\d+)\]/
1077
+
1078
+ if !$regex.match(message)
1079
+ puts "[REGLE] Le message de validation ne suit pas le format"
1080
+ exit 1
1081
+ end
1082
+
1083
+ Avec ce fichier exécutable et à sa place dans `.git/hooks/commit-msg`, si une validation avec un message incorrect est tentée, voici le résultat :
1084
+
1085
+ $ git commit -am 'test'
1086
+ [REGLE] Le message de validation ne suit pas le format
1087
+
1088
+ La validation n'a pas abouti.
1089
+ Néanmoins, si le message contient la bonne forme, Git accepte la validation :
1090
+
1091
+ $ git commit -am 'test [ref: 132]'
1092
+ [master e05c914] test [ref: 132]
1093
+ 1 files changed, 1 insertions(+), 0 deletions(-)
1094
+
1095
+ Ensuite, il faut s'assurer des droits sur les fichiers modifiés.
1096
+ Si le répertoire `.git` du projet contient une copie du fichier d'ACL précédemment utilisé, alors le script `pre-commit` suivant appliquera ses règles :
1097
+
1098
+ #!/usr/bin/env ruby
1099
+
1100
+ $utilisateur = ENV['USER']
1101
+
1102
+ # [ insérer la fonction acl_access_data method ci-dessus ]
1103
+
1104
+ # Ne permet qu'à certains utilisateurs de modifier certains sous-répertoires
1105
+ def verif_perms_repertoire
1106
+ acces = get_acl_access_data('.git/acl')
1107
+
1108
+ fichiers_modifies = `git diff-index --cached --name-only HEAD`.split("\n")
1109
+ fichiers_modifies.each do |chemin|
1110
+ next if chemin.size == 0
1111
+ acces_permis = false
1112
+ acces[$utilisateur].each do |chemin_acces|
1113
+ if !chemin_acces || (chemin.index(chemin_acces) == 0)
1114
+ acces_permis = true
1115
+ end
1116
+ if !acces_permis
1117
+ puts "[ACL] Vous n'avez pas le droit de pousser sur #{path}"
1118
+ exit 1
1119
+ end
1120
+ end
1121
+ end
1122
+
1123
+ verif_perms_repertoire
1124
+
1125
+ C'est grossièrement le même script que celui côté serveur, mais avec deux différences majeures.
1126
+ Premièrement, le fichier ACL est à un endroit différent parce que le script s'exécute depuis le copie de travail et non depuis le répertoire Git.
1127
+ Il faut donc changer le chemin vers le fichier d'ACL de :
1128
+
1129
+ acces = get_acl_access_data('acl')
1130
+
1131
+ en :
1132
+
1133
+ acces = get_acl_access_data('.git/acl')
1134
+
1135
+ L'autre différence majeure réside dans la manière d'obtenir la liste des fichiers modifiés.
1136
+ La fonction sur le serveur la recherche dans le journal des *commits* mais comme dans le cas actuel, le *commit* n'a pas encore été enregistré, il faut chercher la liste dans la zone d'index.
1137
+ Donc au lieu de :
1138
+
1139
+ fichiers_modifies = `git log -1 --name-only --pretty=format:'' #{ref}`
1140
+
1141
+ on utilise :
1142
+
1143
+ fichiers_modifies = `git diff-index --cached --name-only HEAD`
1144
+
1145
+ Mais à ces deux différences près, le script fonctionne de manière identique.
1146
+ Ce script a aussi une autre limitation : il s'attend à ce que l'utilisateur qui le lance localement soit identique à celui sur le serveur distant.
1147
+ S'ils sont différents, il faudra positionner manuellement la variable `$utilisateur`.
1148
+
1149
+ La dernière action à réaliser consiste à vérifier que les références poussées sont bien en avance rapide, mais l'inverse est plutôt rare.
1150
+ Pour obtenir une référence qui n'est pas en avance rapide, il faut soit rebaser après un *commit* qui a déjà été poussé, soit essayer de pousser une branche locale différente vers la même branche distante.
1151
+
1152
+ Comme le serveur indiquera qu'on ne peut pas pousser sans avance rapide de toute façon et que le crochet empêche les poussées forcées, la seule action accidentelle qu'il faut intercepter reste le rebasage de *commits* qui ont déjà été poussés.
1153
+
1154
+ Voici un exemple de script `pre-rebase` qui fait cette vérification.
1155
+ Ce script récupère une liste de tous les *commits* qu'on est sur le point de réécrire et vérifie s'ils existent dans une référence distante.
1156
+ S'il en trouve un accessible depuis une des références distantes, il interrompt le rebasage :
1157
+
1158
+ #!/usr/bin/env ruby
1159
+
1160
+ branche_base = ARGV[0]
1161
+ if ARGV[1]
1162
+ branche_thematique = ARGV[1]
1163
+ else
1164
+ branche_thematique = "HEAD"
1165
+ end
1166
+
1167
+ sha_cibles = `git rev-list #{branche_base}..#{branche_thematique}`.split("\n")
1168
+ refs_distantes = `git branch -r`.split("\n").map { |r| r.strip }
1169
+
1170
+ shas_cibles.each do |sha|
1171
+ refs_distantes.each do |ref_distante|
1172
+ shas_pousses = `git rev-list ^#{sha}^@ refs/remotes/#{ref_distante}`
1173
+ if shas_pousses.split(“\n”).include?(sha)
1174
+ puts "[REGLE] Le commit #{sha} a déjà été poussé sur #{ref_distante}"
1175
+ exit 1
1176
+ end
1177
+ end
1178
+ end
1179
+
1180
+ Ce script utilise une syntaxe qui n'a pas été abordée à la section « sélection de révision » du chapitre 6.
1181
+ La liste des *commits* déjà poussés est obtenue avec cette commande :
1182
+
1183
+ git rev-list ^#{sha}^@ refs/remotes/#{ref_distante}
1184
+
1185
+ La syntaxe `SHA^@` fait référence à tous le parents du *commit*.
1186
+ Les *commits* recherchés sont accessibles depuis le dernier *commit* distant et inaccessibles depuis n'importe quel parent de n'importe quel SHA qu'on cherche à pousser.
1187
+ C'est la définition d'avance rapide.
1188
+
1189
+ La limitation de cette approche reste qu'elle peut s'avérer très lente et non nécessaire.
1190
+ Si vous n'essayez pas de forcer à pousser avec l'option `-f`, le serveur vous avertira et n'acceptera pas la poussée.
1191
+ Cependant, cela reste un exercice intéressant qui peut aider théoriquement à éviter un rebasage qui devra être annulé plus tard.
1192
+
1193
+ ## Résumé ##
1194
+
1195
+ Nous avons traité la plupart des moyens principaux de personnaliser le client et le serveur Git pour mieux l'adapter à toutes les méthodes et les projets.
1196
+ Nous avons couvert toutes sortes de réglages de configurations, d'attributs dans des fichiers et de crochets d'évènement et nous avons construit un exemple de politique de gestion de serveur.
1197
+ Vous voilà prêt à adapter Git à quasiment toutes les gestions dont vous avez rêvé.
1198
+
1199
+ <!-- LocalWords: simplifiez-vous
1200
+ -->