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,1000 @@
1
+ # I comandi interni di Git #
2
+
3
+ Forse sei saltato a questo capitolo da uno precedente, o dopo aver letto il resto del libro. In ogni caso qui approfondiremo il funzionamento interno e l'implementazione di Git. Ho pensato che queste informazioni fossero fondamentali per capire quanto Git fosse utile e potente, ma qualcuno ha argomentato che queste potessero essere complesse e non necessariamente utili per i principianti.
4
+ Per questo motivo ho deciso di includere queste informazioni nell'ultimo capitolo del libro di modo che la possa leggere nella fase dell'apprendimento che ritieni più opportuna. Lascio a te la scelta.
5
+
6
+ Dato che sei qui, possiamo partire. Per prima cosa, se non è ancora chiaro, Git è fondamentalmente un filesystem indirizzabile per contenuto sul quale si appoggia una interfaccia utente VCS. Tra breve imparerai meglio cosa significhi.
7
+
8
+ Nelle prime versioni di Git (principalmente pre 1.5) l'interfaccia utente era molto più complessa perché veniva privilegiato il filesystem rispetto ad avere un VCS pulito. Negli ultimi anni l'interfaccia utente è stata rifinita fino a diventare chiara e facile da usare come gli altri sistemi disponibili, ma è rimasto lo stereotipo che l'interfaccia di Git sia complessa e difficile da capire.
9
+
10
+ Il filesystem indirizzabile per contenuto è veramente formidabile, quindi in questo capitolo inizierò parlandone. Imparerai quindi il meccanismo di trasporto e le attività per la manutenzione del repository con le potresti dover aver a che fare.
11
+
12
+ ## Impianto e sanitari (*Plumbing* e *Porcelain*) ##
13
+
14
+ Questo libro parla di come usare Git utilizzando più di 30 termini come `checkout`, `branch`, `remote` e così via. Poiché Git è stato inizialmente sviluppato come un insieme di strumenti per un VCS, piuttosto che un completo VCS user-friendly, ha un mucchio di termini per fare lavori di basso livello e progettati per essere concatenati insieme nello stile UNIX o invocati da script. Di solito ci si riferisce a questi comandi come "plumbing" (impianto), mentre i comandi più user-friendly sono detti comandi "porcelain" (sanitari).
15
+
16
+ I primi otto capitoli del libro hanno a che fare quasi esclusivamente con comandi *porcelain*. In questo capitolo vedremo invece i comandi *plumbing* di basso livello, perché permettono di accedere al funzionamento interno di Git ed aiutano a dimostrare come e perché Git fa quello che fa. Questi comandi non sono pensati per essere lanciati manualmente dalla linea di comando ma sono da considerare piuttosto come mattoni con i quali costruire nuovi strumenti e script personalizzati.
17
+
18
+ Eseguendo `git init` in una directory nuova o esistente Git provvederà a creare la directory `.git` che contiene praticamente tutto ciò di cui ha bisogno Git. Se vuoi fare un backup o un clone del tuo repository ti basta copiare questa directory da qualche altra parte per avere praticamente tutto quello che ti serve. Tutto questo capitolo tratta il contenuto di questa directory. La sua struttura di default è la seguente:
19
+
20
+ $ ls
21
+ HEAD
22
+ branches/
23
+ config
24
+ description
25
+ hooks/
26
+ index
27
+ info/
28
+ objects/
29
+ refs/
30
+
31
+ Potresti trovare altri file, ma quello che vedi sopra è il risultato di `git init` appena eseguito. La directory `branches` non è utilizzata dalle versioni più recenti di Git e il file `description` è utilizzato solamente dal programma GitWeb, quindi puoi pure ignorarli.
32
+ Il file `config` contiene le configurazioni specifiche per il progetto e la directory `info` mantiene
33
+ un file di exclude globale per ignorare i pattern dei quali non volete tenere traccia un in file .gitignore. La directory `hooks` contiene i tuoi script di hook client/server, che vengono discussi in dettaglio nel capitolo 7.
34
+
35
+ Non abbiamo ancora parlato di quattro cose importanti: i file `HEAD` e `index` e le directory `objects` e `refs`, che fanno parte del nucleo di Git. La directory `objects` contiene tutto il contenuto del tuo database, la directory `refs` contiene i puntatori agli oggetti delle commit nei diversi branch, il file `HEAD` punta al branch di cui hai fatto il checkout e nel file `index` Git registra la informazioni della tua area di staging. Vedremo in dettaglio ognuna di queste sezioni per capire come opera Git.
36
+
37
+ ## Gli oggetti di Git ##
38
+
39
+ Git è un filesystem indirizzabile per contenuto. Magnifico, ma che cosa significa? Significa che il nucleo di Git è un semplice database chiave-valore. Puoi inserire qualsiasi tipo di contenuto
40
+ al suo interno, e ti verrà restituita una chiave che potrai usare per recuperare quel contenuto in qualsiasi momento, quando vorrai. Come dimostrazione puoi usare il comando *plumbing* `hash-object` che accetta dei dati, li salva nella vostra directory `.git` e restituisce la chiave associata ai dati salvati. Per prima cosa create un nuovo repository Git e verificate che la directory `objects` non contenga nulla:
41
+
42
+ $ mkdir test
43
+ $ cd test
44
+ $ git init
45
+ Initialized empty Git repository in /tmp/test/.git/
46
+ $ find .git/objects
47
+ .git/objects
48
+ .git/objects/info
49
+ .git/objects/pack
50
+ $ find .git/objects -type f
51
+ $
52
+
53
+ Git ha creato la directory `objects` e, al suo interno, le subdirectory `pack` e `info`, ma non ci sono file. Ora inseriamo del testo nel tuo database di Git:
54
+
55
+ $ echo 'test content' | git hash-object -w --stdin
56
+ d670460b4b4aece5915caf5c68d12f560a9fe3e4
57
+
58
+ L’opzione `-w` dice a `hash-object` di salvare l'oggetto: se la omettessimo il comando restituirebbe semplicemente quale chiave verrebbe associata all’oggetto. `--stdin` dice al comando di leggere il contenuto dallo standard input: se non lo specifichi `hash-object` si aspetta il percorso di un file. L'output del comando è un checksum di 40 caratteri. Questo è un hash SHA-1, un checksum del contenuto che viene salvato con la sua intestazione, ma questo lo vedremo fra poco. Ora vediamo come Git ha salvato i tuoi dati:
59
+
60
+ $ find .git/objects -type f
61
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
62
+
63
+ Ora troverai un file nella directory `objects`. Questo è il modo in cui Git salva inizialmente il contenuto: un singolo file per ogni porzione di contenuto, con il nome del checksum SHA-1 del contenuto e del suo header. I primi 2 caratteri dello SHA sono il nome della subdirectory, mentre gli altri 38 sono il nome del file.
64
+
65
+ Puoi estrarre il contenuto memorizzato in Git con il comando `cat-file`. Questo comando è una specie di coltellino svizzero per ispezionare gli oggetti Git. Usandolo con l’opzione `-p` è possibile dire al comando `cat-file` d’interpretare il tipo di contenuto e mostrartelo in un modo più elegante:
66
+
67
+ $ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
68
+ test content
69
+
70
+ Ora puoi aggiungere dell’altro contenuto a Git ed estrarlo nuovamente. Lo puoi possibile far anche con il contenuto dei file. Puoi, per esempio, implementare un semplice controllo di versione di un file. Come prima cosa crea un nuovo file e salva il suo contenuto nel database:
71
+
72
+ $ echo 'versione 1' > test.txt
73
+ $ git hash-object -w test.txt
74
+ 83baae61804e65cc73a7201a7252750c76066a30
75
+
76
+ Quindi scrivi un nuovo contenuto nel file e risalvalo:
77
+
78
+ $ echo 'versione 2' > test.txt
79
+ $ git hash-object -w test.txt
80
+ 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
81
+
82
+ Il tuo database conterrà le due nuove versioni del file così come il primo contenuto che avevi già salvato:
83
+
84
+ $ find .git/objects -type f
85
+ .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
86
+ .git/objects/83/baae61804e65cc73a7201a7252750c76066a30
87
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
88
+
89
+ Ora puoi riportare il file alla prima versione:
90
+
91
+ $ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt
92
+ $ cat test.txt
93
+ versione 1
94
+
95
+ o alla seconda:
96
+
97
+ $ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt
98
+ $ cat test.txt
99
+ versione 2
100
+
101
+ Ricordare la chiave SHA-1 di ogni versione del tuo file non è per niente pratico e, come hai visto, non viene salvato nemmeno il nome del file, ma solo il suo contenuto. Questo tipo di oggetto a chiamato blob. Puoi fare in modo che Git ti restituisca il tipo di ciascun oggetto conservato al suo interno, data la sua chiave SHA-1, con `cat-file -t`:
102
+
103
+ $ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
104
+ blob
105
+
106
+ ### L’albero degli oggetti ###
107
+
108
+ Il prossimo argomento che guarderemo è l'albero degli oggetti, che risolve il problema del salvataggio del nome del file e ci permette di salvare un gruppo di file contemporaneamente. Git salva il contenuto in modo simile ad un filesystem UNIX, ma un po’ più semplificato. Tutto il suo contenuto è salvato come albero o blob, dove gli alberi corrispondono alle directory UNIX e i blob corrispondono
109
+ più o meno agli inode o ai contenuti dei file. Un singolo albero contiene una o più voci, ognuna delle quali contiene un puntatore SHA-1 a un blob o a un altro con i suoi modi, tipi e nomi. Ad esempio, l'albero più recente nel progetto simplegit potrebbe assomigliare a questo:
110
+
111
+ $ git cat-file -p master^{tree}
112
+ 100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
113
+ 100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
114
+ 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
115
+
116
+ La sintassi `master^{tree}` indica che l’ultima commit sul tuo branch ‘master’ punta a questo albero.
117
+ Nota che la directory `lib` non è un blob ma un puntatore a un altro albero:
118
+
119
+ $ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
120
+ 100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb
121
+
122
+ Concettualmente, i dati che vengono salvati da Git sono simili a quelli in Figura 9-1.
123
+
124
+ Insert 18333fig0901.png
125
+ Figura 9-1. Versione semplificata del modello dei dati di Git.
126
+
127
+ Puoi creare il tuo albero come vuoi. Git normalmente crea un albero partendo dallo stato della tua area di staging o dall’indice e scrive albero partendo da lì. Quindi, per creare un albero devi prima creare un indice mettendo in staging alcuni file. Per creare un indice con una singola voce - la prima versione del tuo test.txt - puoi usare il comando *plumbing* `update-index`. Usando questo
128
+ comando aggiungi artificialmente la versione precedente del file test.txt a una nuova area di staging.
129
+ Devi usare l'opzione `--add` perché il file non esiste ancora nella tua area di staging (e in effetti ancora non hai nemmeno un'area di staging) e l'opzione `--cacheinfo` perché il file che stai aggiungendo non è nella tua directory ma nel tuo database. Per finire, specifica il modo l’hash SHA-1 e il nome del file:
130
+
131
+ $ git update-index --add --cacheinfo 100644 \
132
+ 83baae61804e65cc73a7201a7252750c76066a30 test.txt
133
+
134
+ In questo caso, stai specificando il modo `100644` che significa che si tratta di un file normale.
135
+ Altre opzioni sono `100755` (che significa che il file è eseguibile) e `120000` (che specifica un link simbolico). Il modo è preso dai modi normali di UNIX, ma è molto meno flessibile: questi tre sono gli unici validi per i file (blob) in Git (anche se ci sono altri modi utilizzati per le directory ed i sottomoduli).
136
+
137
+ Ora puoi usare il comando `write-tree` per creare l'area di staging da un albero. L'opzione `-w`
138
+ non è necessaria, perché l'esecuzione di `write-tree` crea automaticamente un oggetto albero a partire dallo stato dell'indice se l’albero ancora non esiste:
139
+
140
+ $ git write-tree
141
+ d8329fc1cc938780ffdd9f94e0d364e0ea74f579
142
+ $ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
143
+ 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt
144
+
145
+ Puoi anche verificare che si tratta di un oggetto albero:
146
+
147
+ $ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
148
+ tree
149
+
150
+ Ora creerai un nuovo albero con la seconda versione di test.txt e un nuovo file:
151
+
152
+ $ echo ‘nuovo file' > new.txt
153
+ $ git update-index test.txt
154
+ $ git update-index --add new.txt
155
+
156
+
157
+ La tua area di staging ora contiene la nuova versione di test.txt così come il nuovo file new.txt
158
+ Scrivete l'albero (registrando lo stato dell'area di staging o indice in un oggetto albero) e osservate a cosa assomiglia
159
+
160
+ $ git write-tree
161
+ 0155eb4229851634a0f03eb265b69f5a2d56f341
162
+ $ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341
163
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
164
+ 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
165
+
166
+ Nota che questo albero ha entrambe le voci e anche che l’hash SHA di test.txt è lo stesso SHA della precedente "versione 2" (`1f7a7a`). Solo per divertimento, aggiungi il primo albero come subdirectory di questo attuale. Puoi vedere gli alberi nella tua area di staging eseguendo `read-tree`. Potrai vedere un albero esistente nella tua area di staging come sotto-albero con l'opzione `--prefix` di `read-tree`:
167
+
168
+ $ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579
169
+ $ git write-tree
170
+ 3c4e9cd789d88d8d89c1073707c3585e41b0e614
171
+ $ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614
172
+ 040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 bak
173
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
174
+ 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
175
+
176
+ Se hai creato una directory di lavoro dal nuovo albero che hai appena scritto, otterrai i due file nel primo livello della directory e una sotto-directory chiamata `bak`, che contiene la prima versione del file test.txt. Puoi pensare ai dati contenuti da Git per questa strutture come quelli della Figura 9-2.
177
+
178
+ Insert 18333fig0902.png
179
+ Figura 9-2. La struttura dei contenuti per i vostri dati di Git.
180
+
181
+ ### Oggetti Commit ###
182
+
183
+ A questo punto avrai tre alberi che specificano le diverse istantanee (snapshot) del tuo progetto delle quali vuoi tenere traccia, ma rimane il problema iniziale: devi ricordare tutti e tre gli hash SHA-1 per poter recuperare le istantanee. Inoltre non hai nessuna informazione su chi ha salvato le istantanee, né quando le hai salvate né tantomeno perché. Queste sono le informazioni che gli oggetti commit registrano per te.
184
+
185
+ Per creare un oggetto commit esegui `commit-tree` specificando un singolo albero SHA-1 e, se esiste, qual’è la commit immediatamente precedente. Comincia con il primo albero che hai scritto:
186
+
187
+ $ echo 'prima commit' | git commit-tree d8329f
188
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d
189
+
190
+ Ora puoi analizzare il tuo nuovo oggetto commit con `cat-file`:
191
+
192
+ $ git cat-file -p fdf4fc3
193
+ tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
194
+ author Scott Chacon <schacon@gmail.com> 1243040974 -0700
195
+ committer Scott Chacon <schacon@gmail.com> 1243040974 -0700
196
+
197
+ prima commit
198
+
199
+ Il formato di un oggetto commit è semplice: specifica l'albero di primo livello per l’istantanea del progetto in quel dato punto, mentre le informazioni sull’autore delle modifiche o della commit vengono estratte dalle tue impostazioni `user.name` e `user.email` con il timestamp corrente, una linea vuota ed infine il messaggio di commit.
200
+
201
+ Scriviamo gli altri due oggetti commit, ognuno dei quali fa riferimento alla commit che le hanno preceduti:
202
+
203
+ $ echo 'seconda commit' | git commit-tree 0155eb -p fdf4fc3
204
+ cac0cab538b970a37ea1e769cbbde608743bc96d
205
+ $ echo ‘terza commit' | git commit-tree 3c4e9c -p cac0cab
206
+ 1a410efbd13591db07496601ebc7a059dd55cfe9
207
+
208
+ Ognuno dei tre oggetti commit punta ad uno dei tre alberi delle istantanee che hai creato.
209
+ Ora hai una vera e propria cronologia di Git che puoi consultare con il comando `git log`, se lo esegui con l’hash SHA-1 dell'ultima commit vedrai:
210
+
211
+ $ git log --stat 1a410e
212
+ commit 1a410efbd13591db07496601ebc7a059dd55cfe9
213
+ Author: Scott Chacon <schacon@gmail.com>
214
+ Date: Fri May 22 18:15:24 2009 -0700
215
+
216
+ terza commit
217
+
218
+ bak/test.txt | 1 +
219
+ 1 files changed, 1 insertions(+), 0 deletions(-)
220
+
221
+ commit cac0cab538b970a37ea1e769cbbde608743bc96d
222
+ Author: Scott Chacon <schacon@gmail.com>
223
+ Date: Fri May 22 18:14:29 2009 -0700
224
+
225
+ seconda commit
226
+
227
+ new.txt | 1 +
228
+ test.txt | 2 +-
229
+ 2 files changed, 2 insertions(+), 1 deletions(-)
230
+
231
+ commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d
232
+ Author: Scott Chacon <schacon@gmail.com>
233
+ Date: Fri May 22 18:09:34 2009 -0700
234
+
235
+ prima commit
236
+
237
+ test.txt | 1 +
238
+ 1 files changed, 1 insertions(+), 0 deletions(-)
239
+
240
+ Fantastico. Hai appena eseguito tutte le operazioni di basso livello per costruire una cronologia di Git senza utilizzare nessuno dei comandi del front end. Questo è essenzialmente quello che Git fa quando esegui i comandi `git add` e `git commit`: salva i blob per i file che sono cambiati, aggiorna l'indice, scrive gli alberi e scrive gli oggetti commit che fanno riferimento agli alberi di primo livello e le commit immediatamente precedenti a questi. Questi tre oggetti Git principali (il blob, l'albero, e la commit) sono inizialmente salvati come file separati nella tua directory `.git/objects`. Di seguito puoi vedere tutti gli oggetti nella directory di esempio, commentati con quello che contengono:
241
+
242
+ $ find .git/objects -type f
243
+ .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
244
+ .git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
245
+ .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
246
+ .git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
247
+ .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
248
+ .git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
249
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
250
+ .git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
251
+ .git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
252
+ .git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
253
+
254
+ Se segui tutti i puntatori interni otterrai un grafico degli oggetti simile a quelli in Figura 9-3.
255
+
256
+ Insert 18333fig0903.png
257
+ Figura 9-3. Tutti gli oggetti nella tua directory Git.
258
+
259
+ ### Il salvataggio degli oggetti ###
260
+
261
+ In precedenza ho menzionato il fatto che insieme al contenuto viene salvato anche una intestazione. Prendiamoci un minuto per capire come Git salva i propri oggetti. Vedremo come salvare un oggetto blob - in questo caso la stringa "what is up, doc?" - interattivamente con il linguaggio di scripting Ruby. Potete lanciare Ruby in modalità interattiva con il comando `irb`:
262
+
263
+ $ irb
264
+ >> content = "what is up, doc?"
265
+ => "what is up, doc?"
266
+
267
+ Git costruisce una intestazione che comincia con il tipo dell'oggetto, in questo caso un blob, aggiunge uno spazio seguito dalla dimensione del contenuto ed infine da un null byte:
268
+
269
+ >> header = "blob #{content.length}\0"
270
+ => "blob 16\000"
271
+
272
+ Git concatena l’intestazione e il contenuto originale e calcola il checksum SHA-1 del risultato. Puoi calcolare lo SHA-1 di una stringa in Ruby includendo la libreria SHA1 digest con il comando `require` e invocando `Digest::SHA1.hexdigest()`:
273
+
274
+ >> store = header + content
275
+ => "blob 16\000what is up, doc?"
276
+ >> require 'digest/sha1'
277
+ => true
278
+ >> sha1 = Digest::SHA1.hexdigest(store)
279
+ => "bd9dbf5aae1a3862dd1526723246b20206e5fc37"
280
+
281
+ Git comprime il nuovo contenuto con zlib, cosa che potete fare in Ruby con la libreria zlib.
282
+ Prima avrai bisogno di includere la libreria ed invocare `Zlib::Deflate.deflate()` sul contenuto:
283
+
284
+ >> require 'zlib'
285
+ => true
286
+ >> zlib_content = Zlib::Deflate.deflate(store)
287
+ => "x\234K\312\311OR04c(\317H,Q\310,V(-\320QH\311O\266\a\000_\034\a\235"
288
+
289
+ Infine, scrivi il contenuto zlib-deflated in un oggetto sul disco. Determinerai il percorso dell'oggetto che vuoi scrivere (i primi due caratteri dello SHA-1 sono il nome della subdirectory e gli ultimi 38 caratteri sono il nome del file contenuto in quella directory). In Ruby puoi usare la funzione `FileUtils.mkdir_p()` per creare la subdirectory, se questa non esiste. Apri di seguito il file con `File.open()` e scrivi nel file il contenuto ottenuto in precedenza, chiamando
290
+ `write()` sul file handler risultante:
291
+
292
+ >> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
293
+ => ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"
294
+ >> require 'fileutils'
295
+ => true
296
+ >> FileUtils.mkdir_p(File.dirname(path))
297
+ => ".git/objects/bd"
298
+ >> File.open(path, 'w') { |f| f.write zlib_content }
299
+ => 32
300
+
301
+ Questo è tutto - hai creato un oggetto Git valido di tipo blob. Tutti gli oggetti Git sono salvati nello stesso modo, solo con tipi differenti. Invece della stringa blob, l’intestazione comincerà con commit o tree. Inoltre, sebbene il contenuto del blob può essere praticamente qualsiasi cosa, i contenuti commit e tree sono formattati in modo molto dettagliato.
302
+
303
+ ## I riferimenti di Git ##
304
+
305
+ Puoi eseguire un comando come `git log 1a410e` per vedere la cronologia completa, ma devi
306
+ comunque ricordarti che quel `1a410e` è l'ultima commit, per poter essere in grado di vedere la cronologia e trovare quegli oggetti. Hai bisogno di un file nel quale potete salvare il valore dello SHA-1 attribuendogli un semplice nome in modo da poter usare quel nome al posto del valore SHA-1 grezzo.
307
+
308
+ In Git questi sono chiamati "riferimenti" o "refs”: puoi trovare i file che contengono gli hash SHA-1
309
+ nella directory `.git/refs`. Nel nostro progetto questa directory non contiene files ma una semplice struttura:
310
+
311
+ $ find .git/refs
312
+ .git/refs
313
+ .git/refs/heads
314
+ .git/refs/tags
315
+ $ find .git/refs -type f
316
+ $
317
+
318
+ Per creare un nuovo riferimento che ti aiuterà a ricordare dov'è la tua ultima commit, tecnicamente puoi una cosa molto semplice come questo:
319
+
320
+ $ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master
321
+
322
+ Ora puoi usare il riferimento appena creato al posto del valore SHA-1 nei tuoi comandi Git:
323
+
324
+ $ git log --pretty=oneline master
325
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 terza commit
326
+ cac0cab538b970a37ea1e769cbbde608743bc96d seconda commit
327
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d prima commit
328
+
329
+ Questo però non ti incoraggia a modificare direttamente i file di riferimento. Git fornisce un comando sicuro per farlo se vuoi aggiornare un riferimento, chiamato `update-ref`:
330
+
331
+ $ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
332
+
333
+ Questo è quello che si definisce branch in Git: un semplice puntatore o riferimento all’intestazione di un flusso di lavoro. Per creare un branch con la seconda commit, così:
334
+
335
+ $ git update-ref refs/heads/test cac0ca
336
+
337
+ Il tuo branch conterrà solo il lavoro da quella commit in poi:
338
+
339
+ $ git log --pretty=oneline test
340
+ cac0cab538b970a37ea1e769cbbde608743bc96d seconda commit
341
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d prima commit
342
+
343
+ Ora, il tuo database Git assomiglia concettualmente alla Figura 9-4.
344
+
345
+ Insert 18333fig0904.png
346
+ Figura 9-4. La directory degli oggetti Git directory con inclusi i riferimenti branch e head.
347
+
348
+ Quando esegui comandi come `git branch (branchname)`, Git in realtà esegue il comando `update-ref` per aggiungere lo SHA-1 dell'ultima commit del branch nel quale siete, in qualsiasi nuovo riferimento vogliate creare.
349
+
350
+ Se Git non trova un riferimento nella directory `refs` lo cercherà nel file `.git/packed-refs`, che contiene coppie di percorsi con i relativi SHA-1. Per esempio:
351
+
352
+ 52d771167707552d8e2a50f602c669e2ad135722 refs/tags/v1.0.1
353
+
354
+ Questo file esiste per motivi di prestazioni, perché, per riferimenti che non cambiano spesso, è molto più efficiente avere un unico file, piuttosto che tanti piccolissimi. Puoi far comprimere a Git i riferimenti in questo file con il comando `git pack-refs`.
355
+
356
+ ### Intestazione ###
357
+
358
+ La questione ora è questa: quando esegui `git branch (branchname)`, come fa Git a conoscere lo SHA-1 dell'ultima commit? La risposta è nel file HEAD. Il file HEAD è un riferimento simbolico al branch corrente. Per riferimento simbolico intendo che, a differenza di un normale riferimento, normalmente non contiene un valore SHA-1 quanto piuttosto un puntatore a un altro riferimento. Se esamini il file vedrai qualcosa come questa:
359
+
360
+ $ cat .git/HEAD
361
+ ref: refs/heads/master
362
+
363
+ Se esegui `git checkout test`, Git aggiorna il file così:
364
+
365
+ $ cat .git/HEAD
366
+ ref: refs/heads/test
367
+
368
+ Quando esegui `git commit`, questo crea l'oggetto commit specificando il padre dell'oggetto commit in modo che sia un hash SHA-1 a cui fa riferimento l’HEAD.
369
+
370
+ Puoi modificare manualmente questo file, ma, di nuovo, esiste un comando più sicuro per farlo: `symbolic-ref`. Puoi leggere il valore del tuo HEAD tramite questo comando:
371
+
372
+ $ git symbolic-ref HEAD
373
+ refs/heads/master
374
+
375
+ Puoi anche impostare il valore di HEAD:
376
+
377
+ $ git symbolic-ref HEAD refs/heads/test
378
+ $ cat .git/HEAD
379
+ ref: refs/heads/test
380
+
381
+ Non puoi impostare un riferimento simbolico al di fuori dei refs:
382
+
383
+ $ git symbolic-ref HEAD test
384
+ fatal: Refusing to point HEAD outside of refs/
385
+
386
+ ### Tag ###
387
+
388
+ Hai appena visto i tre tipi principali di oggetti in Git, ma ce n'è anche un quarto. L'oggetto tag è molto simile a un oggetto commit: contiene un tag, una data, un messaggio ed un puntatore. La differenza principale sta nel fatto che un tag punta a una commit piuttosto che a un albero. E' come un riferimento a un branch, ma non si muove mai: punta sempre alla stessa commit e gli da un nome più amichevole.
389
+
390
+ Come discusso nel Capitolo 2, ci sono due tipi di tag: annotati (*annotated*) e leggeri (*lightweight*). Puoi creare un tag *lightweight* eseguendo un comando come questo:
391
+
392
+ $ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
393
+
394
+ Questo è tag *lightweight*: un branch che non si muove mai. Un tag annotato è però più complesso. Se crei un tag annotato, Git crea un oggetto tag e scrive un riferimento a cui puntare, piuttosto di puntare direttamente alla commit. Puoi vederlo creando un tag annotato (`-a` specifica che si tratta di un tag annotato):
395
+
396
+ $ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 –m 'test tag'
397
+
398
+ Questo è il valore SHA-1 dell'oggetto creato:
399
+
400
+ $ cat .git/refs/tags/v1.1
401
+ 9585191f37f7b0fb9444f35a9bf50de191beadc2
402
+
403
+ Ora, esegui il comando `cat-file` su questo hash SHA-1:
404
+
405
+ $ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
406
+ object 1a410efbd13591db07496601ebc7a059dd55cfe9
407
+ type commit
408
+ tag v1.1
409
+ tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
410
+
411
+ test tag
412
+
413
+ Noterai che l'oggetto punta all’hash SHA-1 della commit che hai taggato. Nota anche che non ha bisogno di puntare ad una commit: puoi taggare qualsiasi oggetto di Git. Nei sorgenti di Git, per esempio, il mantenitore ha aggiunto la sua chiave pubblica GPG come oggetto blob e lo ha taggato. Puoi vedere la chiave pubblica eseguendo
414
+
415
+ $ git cat-file blob junio-gpg-pub
416
+
417
+ nei sorgenti di Git. Anche il kernel di Linux ha un oggetto tag che non punta ad una commit: il primo tag creato punta all'albero iniziale dell'import dei sorgenti.
418
+
419
+ ### Riferimenti remoti ###
420
+
421
+ Il terzo tipo di riferimento che vedremo è il riferimento remoto. Se aggiungi un repository remoto e poi fai una push, Git salva il valore del quale avete fatto la push, per ogni branch, nella directory `refs/remotes`. Puoi per esempio aggiungere un repository remote di nome `origin`e fare la push del tuo branch `master`:
422
+
423
+ $ git remote add origin git@github.com:schacon/simplegit-progit.git
424
+ $ git push origin master
425
+ Counting objects: 11, done.
426
+ Compressing objects: 100% (5/5), done.
427
+ Writing objects: 100% (7/7), 716 bytes, done.
428
+ Total 7 (delta 2), reused 4 (delta 1)
429
+ To git@github.com:schacon/simplegit-progit.git
430
+ a11bef0..ca82a6d master -> master
431
+
432
+ E puoi vedere quale era il branch `master` del repository remoto `origin` l'ultima volta che hai comunicato con il server esaminando il file `refs/remotes/origin/master`:
433
+
434
+ $ cat .git/refs/remotes/origin/master
435
+ ca82a6dff817ec66f44342007202690a93763949
436
+
437
+ I riferimenti remoti differiscono dai branch (riferimenti in `refs/heads`) principalmente per il fatto
438
+ che non è possibile fare il checkout di quest'ultimi. Git li sposta come segnalibri affinché corrispondano all'ultimo stato conosciuto di quei branch sul server.
439
+
440
+ ## Pacchetti di file ##
441
+
442
+ Torniamo agli oggetti del database per il tuo repository Git di test. A questo punto hai 11 oggetti: 4 blob, 3 tree, 3 commit, e 1 tag:
443
+
444
+ $ find .git/objects -type f
445
+ .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
446
+ .git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
447
+ .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
448
+ .git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
449
+ .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
450
+ .git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag
451
+ .git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
452
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
453
+ .git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
454
+ .git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
455
+ .git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
456
+
457
+ Git comprime il contenuto di questi file con zlib e, poiché non stai memorizzando molte cose, complessivamente tutti questi file occupano solo 925 bytes. Aggiungeremo al repository del contenuto più pesante per dimostrare un’interessante caratteristica di Git. Aggiungi il file repo.rb dalla libreria Grit che abbiamo visto prima: sono circa 12K di sorgenti:
458
+
459
+ $ curl -L http://github.com/mojombo/grit/raw/master/lib/grit/repo.rb > repo.rb
460
+ $ git add repo.rb
461
+ $ git commit -m ‘aggiunto repo.rb'
462
+ [master 484a592] aggiunto repo.rb
463
+ 3 files changed, 459 insertions(+), 2 deletions(-)
464
+ delete mode 100644 bak/test.txt
465
+ create mode 100644 repo.rb
466
+ rewrite test.txt (100%)
467
+
468
+ Se guardi l’albero dopo questa nuova commit, vedrai l’hash SHA-1 che l’oggetto blob per repo.rb:
469
+
470
+ $ git cat-file -p master^{tree}
471
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
472
+ 100644 blob 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e repo.rb
473
+ 100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
474
+
475
+ Puoi quindi usare `git cat-file` per vedere le dimensioni dell’oggetto:
476
+
477
+ $ git cat-file -s 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e
478
+ 12898
479
+
480
+ Modifica un po’ il file e guarda che succede:
481
+
482
+ $ echo '# testing' >> repo.rb
483
+ $ git commit -am 'modificato un poco il repository'
484
+ [master ab1afef] modificato un poco il repository
485
+ 1 files changed, 1 insertions(+), 0 deletions(-)
486
+
487
+ Verificando l’albero risultate da questa commit vedrai qualcosa d’interessante:
488
+
489
+ $ git cat-file -p master^{tree}
490
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
491
+ 100644 blob 05408d195263d853f09dca71d55116663690c27c repo.rb
492
+ 100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
493
+
494
+ Il blob è un oggetto differente, cioè, nonostante tu abbia aggiunto una sola riga alla fine di un file da 400 righe, Git memorizza il nuovo contenuto come un oggetto completamente nuovo:
495
+
496
+ $ du -b .git/objects/05/408d195263d853f09dca71d55116663690c27c
497
+ 4109 .git/objects/05/408d195263d853f09dca71d55116663690c27c
498
+
499
+ Ora hai sul disco due oggetti quasi identici da 4K. Non sarebbe carino se Git potesse memorizzarne solo una per intero e del secondo solo la differenza col primo?
500
+
501
+ In effetti può farlo. Il formato iniziale con cui Git salva l’oggetto sul disco con un formato cosiddetto sciolto (*loose*). Però, occasionalmente, Git compatta molti di questi oggetti in un singolo file binario detto “pacchetto di file” (*packfile*) per risparmiare spazio ed essere più efficiente. Git lo fa se hai molti oggetti sciolti sparpagliati, se esegui il comando `git gc` o se fai la push verso un server remoto. Puoi farlo manualmente, per vedere cosa succede, eseguendo il comando `git gc`, che forza Git a comprimere gli oggetti:
502
+
503
+ $ git gc
504
+ Counting objects: 17, done.
505
+ Delta compression using 2 threads.
506
+ Compressing objects: 100% (13/13), done.
507
+ Writing objects: 100% (17/17), done.
508
+ Total 17 (delta 1), reused 10 (delta 0)
509
+
510
+ Se consulti la directory degli oggetti, vedrai che molti dei tuoi oggetti sono scomparsi, ma ne sono apparsi un paio nuovo:
511
+
512
+ $ find .git/objects -type f
513
+ .git/objects/71/08f7ecb345ee9d0084193f147cdad4d2998293
514
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
515
+ .git/objects/info/packs
516
+ .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx
517
+ .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack
518
+
519
+ Gli oggetti rimanenti sono i blob che non puntano a nessuna commit: in questo caso gli esempi "what is up, doc?" e "test content" creati precedentemente. Poiché non li abbiamo ancora aggiunti a nessuna commit, vengono considerati Because you never added them to any commits, they’re considered dondolanti (*dangling*) e non sono compressi nei pacchetto appena creato.
520
+
521
+ I nuovi file sono il pacchetto e un indice. Il pacchetto è un singolo file contenente tutti gli altri oggetti che sono stati rimossi dal filesystem. L’indice è un file che contiene gli offset degli oggetti contenuti nel pacchetto per trovare velocemente un oggetto specifico. La cosa interessante è che, sebbene gli oggetti occupassero 12K sul disco prima dell’esecuzione di `gc`, il nuovo pacchetto è di soli 6K. Hai dimezzato lo spazio usato sul disco comprimendo gli oggetti.
522
+
523
+ Git come ci riesce? Quando Git comprime gli oggetti, cerca prima i file che hanno lo stesso nome e dimensioni simili, e memorizza solo le differenze tra i singoli file. Puoi controllare dentro il pacchetto e vedere cos’ha fatto Git per risparmiare spazio. Il comando *plumbing* `git verify-pack` ti permette di vedere cos’è stato compresso:
524
+
525
+ $ git verify-pack -v \
526
+ .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx
527
+ 0155eb4229851634a0f03eb265b69f5a2d56f341 tree 71 76 5400
528
+ 05408d195263d853f09dca71d55116663690c27c blob 12908 3478 874
529
+ 09f01cea547666f58d6a8d809583841a7c6f0130 tree 106 107 5086
530
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 commit 225 151 322
531
+ 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob 10 19 5381
532
+ 3c4e9cd789d88d8d89c1073707c3585e41b0e614 tree 101 105 5211
533
+ 484a59275031909e19aadb7c92262719cfcdf19a commit 226 153 169
534
+ 83baae61804e65cc73a7201a7252750c76066a30 blob 10 19 5362
535
+ 9585191f37f7b0fb9444f35a9bf50de191beadc2 tag 136 127 5476
536
+ 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e blob 7 18 5193 1 \
537
+ 05408d195263d853f09dca71d55116663690c27c
538
+ ab1afef80fac8e34258ff41fc1b867c702daa24b commit 232 157 12
539
+ cac0cab538b970a37ea1e769cbbde608743bc96d commit 226 154 473
540
+ d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree 36 46 5316
541
+ e3f094f522629ae358806b17daf78246c27c007b blob 1486 734 4352
542
+ f8f51d7d8a1760462eca26eebafde32087499533 tree 106 107 749
543
+ fa49b077972391ad58037050f2a75f74e3671e92 blob 9 18 856
544
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d commit 177 122 627
545
+ chain length = 1: 1 object
546
+ pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack: ok
547
+
548
+ Dove il blob `9bc1d`, che ricorderai era la prima versione del file repo.rb, è referenziato dal blob `05408`, che era la seconda versione. La terza colonna indica la dimensione degli oggetti nel pacchetto, e puoi vedere che `05408` occupa 12K, ma `9bc1d` solo 7 bytes. Un’altra cosa interessante è che la seconda versione del file è quella che è stata memorizzata intatta, mentre della versione originale è stato memorizzata solo il delta: questo perché è molto più probabile che avrai bisogno di accedere più velocemente alla versione più recente di un file.
549
+
550
+ La cosa ancora più interessante è che può essere ricompresso in qualsiasi momento. Git ricomprime automaticamente il tuo database cercando sempre di risparmiare spazio. Puoi comunque ricomprimere il tuo database manualmente in qualsiasi momento, eseguendo il comando `git gc`.
551
+
552
+ ## Le specifiche di riferimento (*refspec*) ##
553
+
554
+ In questo libro abbiamo sempre usato delle semplici mappature, dai branch remoti ai riferimenti locali, ma possono essere anche molto più complessi.
555
+ Immagina di aggiungere un repository remoto:
556
+
557
+ $ git remote add origin git@github.com:schacon/simplegit-progit.git
558
+
559
+ Questo aggiunge una sezione al tuo `.git/config` specificando, del repository remoto, il nome (`origin`), l’URL e le specifiche di riferimento per ottenere le modifiche remote:
560
+
561
+ [remote "origin"]
562
+ url = git@github.com:schacon/simplegit-progit.git
563
+ fetch = +refs/heads/*:refs/remotes/origin/*
564
+
565
+ Il formato delle specifiche di riferimento è un `+` (opzionale) seguito da `<src>:<dst>`, dove `<src>` è lo schema per i riferimenti remoti e `<dst>` per gli stessi salvati in locale. Il `+` dice a Git di aggiornare i riferimenti anche se non si tratta di un avanti-veloce (*fast-forward*).
566
+
567
+ Nel caso predefinito, che viene scritto da git quando si usa il comando `git remote add`, Git recupera tutti i riferimenti sul server di `refs/heads/` e li scrive localmente in `refs/remotes/origin/`. Quindi, se hai un branch `master` sul server, puoi accedere localmente al log di questo branch così:
568
+
569
+ $ git log origin/master
570
+ $ git log remotes/origin/master
571
+ $ git log refs/remotes/origin/master
572
+
573
+ Sono tutti equivalenti perché Git li espande tutti a `refs/remotes/origin/master`.
574
+
575
+ Se vuoi, invece di scaricare tutti i branch dal server, Git può scaricare solo il `master` cambiando la riga del fetch così
576
+
577
+ fetch = +refs/heads/master:refs/remotes/origin/master
578
+
579
+ Questa è la specifica di riferimento predefinito per questo repository remoto quando si esegue il comando `git fetch`. Se vuoi fare qualcosa una sola volta, puoi sempre specificare le specifiche di riferimento alla riga di comando. Per fare un *pull* del `master` sul repository remoto dal branch locale `origin/mymaster`, puoi eseguire
580
+
581
+ $ git fetch origin master:refs/remotes/origin/mymaster
582
+
583
+ Puoi anche specificare più specifiche di riferimento alla riga di comando, per fare una *pull* di più branch allo stesso tempo:
584
+
585
+ $ git fetch origin master:refs/remotes/origin/mymaster \
586
+ topic:refs/remotes/origin/topic
587
+ From git@github.com:schacon/simplegit
588
+ ! [rejected] master -> origin/mymaster (non fast forward)
589
+ * [new branch] topic -> origin/topic
590
+
591
+ In questo caso la *pull* verso il master è stata rifiutata perché non era un riferimento *fast-forward*. Puoi modificare questo comportamento aggiungendo un `+` prima delle specifiche di riferimento.
592
+
593
+ Puoi anche specificare più specifiche di riferimento nel tuo file di configurazione. Se vuoi prendere sempre il master e il branch sperimentale puoi aggiungere queste due righe:
594
+
595
+ [remote "origin"]
596
+ url = git@github.com:schacon/simplegit-progit.git
597
+ fetch = +refs/heads/master:refs/remotes/origin/master
598
+ fetch = +refs/heads/experiment:refs/remotes/origin/experiment
599
+
600
+ Non puoi usare schemi parziali, e quindi l’impostazione seguente non è valida:
601
+
602
+ fetch = +refs/heads/qa*:refs/remotes/origin/qa*
603
+
604
+ Ma puoi usare la nomenclatura per ottenere lo stesso risultato. Se hai un gruppo di QA che faccia la *push* di una serie di branch e tu vuoi prendere il master e qualsiasi branch del gruppo di QA e nient’altro, puoi usare questa configurazione:
605
+
606
+ [remote "origin"]
607
+ url = git@github.com:schacon/simplegit-progit.git
608
+ fetch = +refs/heads/master:refs/remotes/origin/master
609
+ fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*
610
+
611
+ Se hai un flusso di lavoro complesso, dove il gruppo di QA e gli sviluppatori fanno la *push* di branch e il gruppo d’integrazione che fa la push e collabora su branch remoti, puoi enumerarli facilmente come abbiamo appena visto.
612
+
613
+ ### Le push con le specifiche di riferimento ###
614
+
615
+ È bello che tu possa nominare i riferimenti in questo modo, ma come fanno, in primo luogo, i membri del gruppo di QA a mettere i loro branch in `qa/`? Puoi farlo usando le specifiche di riferimento anche per la *push*.
616
+
617
+ Se il gruppo di QA vuole fare la *push* del loro `master` in `qa/master` sul server remoto, possono eseguire
618
+
619
+ $ git push origin master:refs/heads/qa/master
620
+
621
+ Se vogliono che Git lo faccia automaticamente ogni volta che eseguano `git push origin` basta che aggiungano una riga `push` al loro file di configurazione:
622
+
623
+ [remote "origin"]
624
+ url = git@github.com:schacon/simplegit-progit.git
625
+ fetch = +refs/heads/*:refs/remotes/origin/*
626
+ push = refs/heads/master:refs/heads/qa/master
627
+
628
+ Questo fa si che eseguendo `git push origin`, Git faccia sempre una *push* del `master` locale in `qa/master` del server remoto.
629
+
630
+ ### Eliminare i riferimenti ###
631
+
632
+ Puoi usare le specifiche di riferimento anche per eliminare dei riferimenti ai server remoti:
633
+
634
+ $ git push origin :topic
635
+
636
+ Poiché il formato delle specifiche è `<src>:<dst>`, omettendo la parte `<src>` è come dire che il branch remoto è “niente” e quindi lo si cancella.
637
+
638
+ ## Protocolli di trasferimento ##
639
+
640
+ Git può trasferire i dati tra i repository principalmente in due modi: attraverso l’HTTP e i c.d. protocolli intelligenti come usati da `file://`, `ssh://`, e `git://`. Questa sezione mostra rapidamente come funzionano questi protocolli.
641
+
642
+ ### Il protocollo muto ###
643
+
644
+ Il trasferimento di Git attraverso l’HTTP viene spesso anche definito come protocollo muto perché non richiede di eseguire nessun codice specifico di Git durante il processo di trasferimento. Il processo per prendere gli aggiornamenti consiste in una serie di richieste GET, con il client che presuppone la struttura del repository Git sul server. Seguiamo il processo `http-fetch` per la libreria simplegit:
645
+
646
+ $ git clone http://github.com/schacon/simplegit-progit.git
647
+
648
+ La prima cosa che fa questo comando è scaricare il file `info/refs` che viene scritto dal comando `update-server-info`, che è il motivo per cui hai bisogno di abilitare l’hook `post-receive` perché il trasferimento su HTTP funzioni bene:
649
+
650
+ => GET info/refs
651
+ ca82a6dff817ec66f44342007202690a93763949 refs/heads/master
652
+
653
+ Ora hai una lista dei riferimenti remoti e dei vari hash SHA e cerchi quindi a cosa fa riferimento l’HEAD per sapere di cosa devi fare il check out quando avrai finito:
654
+
655
+ => GET HEAD
656
+ ref: refs/heads/master
657
+
658
+ Dovrai quindi fare il check out del `master` quando avrai finito di scaricare tutto.
659
+ A questo punto sei pronti per iniziare il processo. Poiché il tuo punto di partenza è la commit `ca82a6`, che abbiamo trovato nel file `info/refs`, inizierai scaricandola così:
660
+
661
+ => GET objects/ca/82a6dff817ec66f44342007202690a93763949
662
+ (179 bytes of binary data)
663
+
664
+ Riceverai un oggetto, che sul server è in formato sciolto, attraverso una richiesta GET del protocollo HTTP. Puoi decomprimere l’oggetto con zlib, rimuovere l’intestazione e vedere il contenuto della commit:
665
+
666
+ $ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
667
+ tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
668
+ parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
669
+ author Scott Chacon <schacon@gmail.com> 1205815931 -0700
670
+ committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
671
+
672
+ changed the version number
673
+
674
+ Ora hai altri due oggetti da scaricare: `cfda3b`, che è l’albero a cui fa riferimento la commit che abbiamo appena scaricato, e `085bb3`, che è la commit precedente:
675
+
676
+ => GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
677
+ (179 bytes of data)
678
+
679
+ Che ti restituisce il seguente oggetto commit e scarica l’albero:
680
+
681
+ => GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
682
+ (404 - Non trovato)
683
+
684
+ Oops: sembra che l’oggetto sul server non sia in formato sciolto, e per questo hai ricevuto un errore 404. Ci sono un paio di ragioni per cui questo possa accadere: l’oggetto potrebbe essere in un altro repository o potrebbe essere in un pacchetto (*packfile*). Git cerca prima la lista dei repository alternativi:
685
+
686
+ => GET objects/info/http-alternates
687
+ (file vuoto)
688
+
689
+ E se questa restituisce una lista di URL alternativi, Git cerca sui repository elencati i file sciolti e i pacchetti: questo è un buon meccanismo per progetti che sono uno la biforcazione dell’altro per condividere gli oggetti sul disco. Poiché però nel nostro caso non c’è nessun repository alternativo, l’oggetto che cerchiamo dev’essere in un pacchetto. Per sapere quali pacchetti sono disponibili sul server, devi scaricare il file `objects/info/packs`, che contiene la lista di tutti i pacchetti (questo file viene generato anche da `update-server-info`):
690
+
691
+ => GET objects/info/packs
692
+ P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
693
+
694
+ Sul nostro server c’è un solo pacchetto, quindi il nostro oggetto è ovviamente lì, ma cercheremo l’indice per esserne sicuri. Questo è utile nel caso abbia più pacchetti sul server, così puoi scoprire quale pacchetto contiene l’oggetto di cui hai bisogno:
695
+
696
+ => GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
697
+ (4k of binary data)
698
+
699
+ Ora che hai l’indice del pacchetto, puoi vedere quali oggetti contiene perché questo contiene tutti gli hash SHA degli oggetti contenuti nel pacchetto e gli offset degli oggetti. L’oggetto è lì e quindi scaricheremo l’intero pacchetto:
700
+
701
+ => GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
702
+ (13k of binary data)
703
+
704
+ Hai tre oggetti albero e puoi quindi continuare a percorrere le commit. Sono tutte nello stesso pacchetto che hai appena scaricato, così non devi fare ulteriori richieste al tuo server. Git crea una copia di lavoro con un check out del branch `master` riferito dal puntatore HEAD che hai scaricato all’inizio.
705
+
706
+ L’intero output di questo processo appare così:
707
+
708
+ $ git clone http://github.com/schacon/simplegit-progit.git
709
+ Initialized empty Git repository in /private/tmp/simplegit-progit/.git/
710
+ got ca82a6dff817ec66f44342007202690a93763949
711
+ walk ca82a6dff817ec66f44342007202690a93763949
712
+ got 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
713
+ Getting alternates list for http://github.com/schacon/simplegit-progit.git
714
+ Getting pack list for http://github.com/schacon/simplegit-progit.git
715
+ Getting index for pack 816a9b2334da9953e530f27bcac22082a9f5b835
716
+ Getting pack 816a9b2334da9953e530f27bcac22082a9f5b835
717
+ which contains cfda3bf379e4f8dba8717dee55aab78aef7f4daf
718
+ walk 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
719
+ walk a11bef06a3f659402fe7563abf99ad00de2209e6
720
+
721
+ ### Protocolli intelligenti ###
722
+
723
+ Usare l’HTTP è un metodo semplice ma inefficiente. È molto più comune usare i protocolli intelligenti per il trasferimento dei dati. Questi protocolli usano un processo sul server remoto che conosce Git intelligentemente: possono leggere i dati locali e capire quali dati sono già sul client e quali devono invece essere trasferiti e generare quindi un flusso di dati personalizzato. Ci sono due gruppi di processi per trasferire i dati: una coppia per inviarli e una per scaricarli.
724
+
725
+ #### Inviare dati ####
726
+
727
+ Per inviare dati a un server remoto, Git usa i processi `send-pack` e `receive-pack`. Il processo `send-pack` viene eseguito sul client e lo connette al processo `receive-pack` sul server remoto.
728
+
729
+ Diciamo, per esempio, che esegui il comando `git push origin master` nel tuo progetto, e `origin` è un URL che usa il protocollo SSH. Git avvia il processo `send-pack` che stabilisce una connessione al server con SSH e cerca di eseguire un comando sul server attraverso SSH:
730
+
731
+ $ ssh -x git@github.com "git-receive-pack 'schacon/simplegit-progit.git'"
732
+ 005bca82a6dff817ec66f4437202690a93763949 refs/heads/master report-status delete-refs
733
+ 003e085bb3bcb608e1e84b2432f8ecbe6306e7e7 refs/heads/topic
734
+ 0000
735
+
736
+ Il comando `git-receive-pack` risponde immediatamente con una riga per ogni riferimento che memorizza (in questo caso solo il branch `master` e i suoi hash SHA). La prima riga indica anche quali sono le operazioni possibili sul server (nel nostro caso `report-status` e `delete-refs`).
737
+
738
+ Ogni riga inizia con un valore esadecimale da 4 byte che specifica la lunghezza del resto della riga. La nostra prima riga inizia con 005b, ovvero 91 in esadecimale, che significa che su questa riga restano altri 91 bytes. La riga successiva inizia con 003e, ovvero 62, e quindi leggerai gli altri 62 bytes. La riga successiva è 0000, che significa che la lista dei riferimenti sul server è finita.
739
+
740
+ Ora che conosce lo stato del server, il tuo processo `send-pack` determina quali commit hai in locale e quali no. Per ogni riferimento che verrà aggiornato con questa push, il processo `send-pack` invia le informazioni al processo `receive-pack`. Per esempio, se stai aggiornando il branch `master` e aggiungendo il branch `experiment`, la risposta del `send-pack` sarà più o meno così:
741
+
742
+ 0085ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 refs/heads/master report-status
743
+ 00670000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d refs/heads/experiment
744
+ 0000
745
+
746
+ L’hash SHA-1 di tutti '0' significa che prima non c’era niente, perché stiamo aggiungendo il riferimento al branch sperimentale. Se invece stai cancellando un riferimento, vedrai l’opposto: gli ‘0’ saranno sul lato destro.
747
+
748
+ Git invia una riga per ogni riferimento che si sta aggiornando con l’SHA precedente, il nuovo e il riferimento che si sta aggiornando. La prima riga indica anche le operazioni possibili sul client. Il client invia al server un pacchetto con tutti gli oggetti che non ci sono ancora sul server e il server conclude il trasferimento indicando che il trasferimento è andato a buon fine o è fallito):
749
+
750
+ 000Aunpack ok
751
+
752
+ #### Scaricare dati ####
753
+
754
+ Quando scarichi dei dati vengono invocati i processi `fetch-pack` e `upload-pack`. Il client avvia il processo `fetch-pack` che si connette al processo `upload-pack`, sul server remoto, per definire i dati che dovranno essere scaricati.
755
+
756
+ Ci sono diversi modi per avviare il processo `upload-pack` sul repository remote. Puoi eseguirlo con SSH, come abbiamo fatto per il processo `receive-pack`, ma puoi anche avviarlo con il demone Git, che si mette in ascolto sulla porta 9418. Una volta connesso, il processo `fetch-pack` invia al demone remoto una serie di dati che assomigliano a questi:
757
+
758
+ 003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0
759
+
760
+ Inizia con 4 byte che indicano la quantità dei dati che seguiranno, quindi il comando da eseguire seguito da un byte *null* quindi il nome del server seguito da un altro byte *null*. Il demone Git verifica che il comando richiesto possa essere eseguito, che il repository esista e che sia accessibile pubblicamente. Se tutto va bene, avvia processo `upload-pack` e gli passa il controllo della request.
761
+
762
+ Se stai prendendo i dati con l’SSH, `fetch-pack` eseguirà qualcosa del genere:
763
+
764
+ $ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"
765
+
766
+ In entrambi i casi, dopo la connessione di `fetch-pack`, `upload-pack` restituisce qualcosa del genere:
767
+
768
+ 0088ca82a6dff817ec66f44342007202690a93763949 HEAD\0multi_ack thin-pack \
769
+ side-band side-band-64k ofs-delta shallow no-progress include-tag
770
+ 003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
771
+ 003e085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 refs/heads/topic
772
+ 0000
773
+
774
+ Questa risposta è simile a quella di `receive-pack`, ma ha delle caratteristiche diverse. Invia, in aggiunta, il riferimento all’HEAD così che se si sta facendo un clone, il client sappia di cosa debba fare il checkout.
775
+
776
+ A questo punto il processo `fetch-pack` cerca quali oggetti ha già e risponde indicando gli oggetti di cui ha bisogno, inviando un "want" (voglio) e gli SHA che vuole. Invia anche gli hash degli oggetti che ha già, preceduti da "have" (ho). Alla fine di questa lista scrive "done" (fatto), per invitare il processo `upload-pack` a inviare il pacchetto con i dati di cui hai bisogno:
777
+
778
+ 0054want ca82a6dff817ec66f44342007202690a93763949 ofs-delta
779
+ 0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
780
+ 0000
781
+ 0009done
782
+
783
+ Questo è il caso più semplice del protocollo di trasferimento. Nei casi più complessi il client supporta anche i metodi `multi_ack` o `side-band`, ma questo esempio mostra l’andirivieni dei processi del protocollo intelligente.
784
+
785
+ ## Manutenzione e recupero dei dati ##
786
+
787
+ A volte può essere necessario fare un po’ di pulizia del repository per renderlo più compatto, per ripulire un repository importato o recuperare del lavoro che è andato perso. Questa sezione tratta alcuni di questi scenari.
788
+
789
+ ### Manutenzione ###
790
+
791
+ Git, occasionalmente, esegue automaticamente il comando "auto gc". Il più delle volte questo comando non fa niente, ma se ci sono troppi oggetti sciolti (oggetti che non sono compressi in un pacchetto) o troppi pacchetti, Git esegue un vero e proprio `git gc`. `gc` sta per *garbage collect* (raccolta della spazzatura), e il comando fa una serie di cose:: raccoglie tutti gli oggetti sciolti e li compatta in un pacchetto, consolida i pacchetti in un pacchetto più grande e cancella gli oggetti che non sono raggiungibili da nessuna commit e siano più vecchi di qualche mese.
792
+
793
+ Puoi eseguire il comando “auto gc” così:
794
+
795
+ $ git gc --auto
796
+
797
+ Questo, lo ripetiamo, generalmente non farà niente: dovrai avere circa 7.000 oggetti sciolti o più di 50 pacchetti perché Git esegua la garbage collection vera e propria. Puoi modificare questi limiti cambiando, rispettivamente, i valori di `gc.auto` e `gc.autopacklimit` delle tue configurazioni.
798
+
799
+ Un’altra cosa che fa `gc` è quella di impacchettare i tuoi riferimenti in un singolo file. Immagina che il tuo repository contenga i branch e i tag seguenti:
800
+
801
+ $ find .git/refs -type f
802
+ .git/refs/heads/experiment
803
+ .git/refs/heads/master
804
+ .git/refs/tags/v1.0
805
+ .git/refs/tags/v1.1
806
+
807
+ Se esegui `git gc` non avrai più questi file nella directory `refs` perché Git li sposterà, in nome dell’efficienza, in un file chiamato `.git/packed-refs`, che apparirà così:
808
+
809
+ $ cat .git/packed-refs
810
+ # pack-refs with: peeled
811
+ cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
812
+ ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
813
+ cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
814
+ 9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
815
+ ^1a410efbd13591db07496601ebc7a059dd55cfe9
816
+
817
+ Se aggiorni un riferimento, Git non modificherà questo file, ma scriverà un nuovo file nella directory `refs/heads`. Per conoscere l’hash SHA di uno specifico riferimento, Git controlla se è nella directory `refs` e poi nel file `packed-refs` se non lo trova. In ogni caso, se non trovi un riferimento nella directory `refs`, questo sarà probabilmente sarà nel file `packed-refs`.
818
+
819
+ Nota l’ultima riga del file, quella che inizia con un `^`. Questo indica che il tag immediatamente precedente è un tag annotato e che quella linea è la commit a cui punta il tag annotato.
820
+
821
+ ### Recupero dei dati ###
822
+
823
+ Durante il tuo lavoro quotidiano può capitare che, accidentalmente, perda una commit. Questo generalmente succede quando forzi la cancellazione di un branch su cui hai lavorato e poi scopri di averne bisogno, o quando fai un hard-reset di un branch, abbandonando quindi delle commit da cui poi vorrai qualcosa. Ipotizzando che sia successo proprio questo: come fai a ripristinare le commit perse?
824
+
825
+ Qui c’è un esempio di un hard-resets del master nel tuo repository di test su una vecchia commit e recuperare poi le commit perse. Prima di tutto verifica lo stato del tuo repository:
826
+
827
+ $ git log --pretty=oneline
828
+ ab1afef80fac8e34258ff41fc1b867c702daa24b modificato un poco il repository
829
+ 484a59275031909e19aadb7c92262719cfcdf19a aggiunto repo.rb
830
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 terza commit
831
+ cac0cab538b970a37ea1e769cbbde608743bc96d seconda commit
832
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d prima commit
833
+
834
+ Muovi ora il branch `master` a una commit centrale:
835
+
836
+ $ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
837
+ HEAD is now at 1a410ef terza commit
838
+ $ git log --pretty=oneline
839
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 terza commit
840
+ cac0cab538b970a37ea1e769cbbde608743bc96d seconda commit
841
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d prima commit
842
+
843
+ Così facendo hai perso le due commit più recenti: questa commit non sono più raggiungibili in nessun modo. Devi scoprire l’hash SHA dell’ultima commit e aggiungere quindi un branch che vi punti. Il trucco è trovare l’hash SHA dell’ultima commit: non è come lo ricordavi, vero?
844
+
845
+ Spesso il modo più veloce è usare `git reflog`. Mentre lavori Git memorizza silenziosamente lo stato del tuo HEAD ogni volta che lo cambi. Il reflog viene aggiornato ogni volta che fai una commit o cambi un branch. Il reflog viene aggiornato anche dal comando `git update-ref`, che è un’altra buona ragione per usarlo, invece di scrivere direttamente il valore dell’SHA nei tuoi file ref, come abbiamo visto nella sezione “I Riferimenti di Git" in questo stesso capitolo. Eseguendo `git reflog` puoi vedere dov’eri in qualsiasi dato momento:
846
+
847
+ $ git reflog
848
+ 1a410ef HEAD@{0}: 1a410efbd13591db07496601ebc7a059dd55cfe9: updating HEAD
849
+ ab1afef HEAD@{1}: ab1afef80fac8e34258ff41fc1b867c702daa24b: updating HEAD
850
+
851
+ Qui vediamo le due commit di cui abbiamo fatto il checkout, ma qui non ci sono poi tante informazioni. Per vedere le stesse informazioni, ma in una maniera più utile, possiamo eseguire il comando `git log -g`, che restituisce un output normale del tuo reflog.
852
+
853
+ $ git log -g
854
+ commit 1a410efbd13591db07496601ebc7a059dd55cfe9
855
+ Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
856
+ Reflog message: updating HEAD
857
+ Author: Scott Chacon <schacon@gmail.com>
858
+ Date: Fri May 22 18:22:37 2009 -0700
859
+
860
+ terza commit
861
+
862
+ commit ab1afef80fac8e34258ff41fc1b867c702daa24b
863
+ Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
864
+ Reflog message: updating HEAD
865
+ Author: Scott Chacon <schacon@gmail.com>
866
+ Date: Fri May 22 18:15:24 2009 -0700
867
+
868
+ modificato un poco il repository
869
+
870
+ It looks like the bottom commit is the one you lost, so you can recover it by creating a new branch at that commit. For example, you can start a branch named `recover-branch` at that commit (ab1afef):
871
+
872
+ $ git branch recover-branch ab1afef
873
+ $ git log --pretty=oneline recover-branch
874
+ ab1afef80fac8e34258ff41fc1b867c702daa24b modificato un poco il repository
875
+ 484a59275031909e19aadb7c92262719cfcdf19a aggiunto repo.rb
876
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 terza commit
877
+ cac0cab538b970a37ea1e769cbbde608743bc96d seconda commit
878
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d prima commit
879
+
880
+ Bello: ora sembra che tu abbia un branch chiamato `recover-branch` dov’era il tuo branch `master` precedentemente, rendendo nuovamente raggiungibili le due commit.
881
+ Immagina che le commit perse, per qualche ragione, non appaiano nel reflog: puoi simularlo cancellando il branch `recover-branch` e il reflog. Ora le due commit non sono più raggiungibili da niente:
882
+
883
+ $ git branch -D recover-branch
884
+ $ rm -Rf .git/logs/
885
+
886
+ Poiché i dati del reflog è conservato nella directory `.git/logs/`, ora effettivamente non hai nessun reflog. A questo punto come possiamo recuperare la commit? Uno dei modi è usare l’utility `git fsck`, che verifica l’integrità del database del tuo repository. Se lo esegui con l’opzione `--full` ti mostrerà tutti gli oggetti che non sono collegati a nessun altro oggetto:
887
+
888
+ $ git fsck --full
889
+ dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
890
+ dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
891
+ dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
892
+ dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
893
+
894
+ In questo caso rivediamo la commit scomparsa dopo la *dangling commit* e la puoi recuperare creando un branch che punti al suo SHA.
895
+
896
+ ### Eliminare oggetti ###
897
+
898
+ Ci sono un sacco di grandi cose in Git, ma una delle caratteristiche che può creare qualche problemi è che la `git clone` scarica l’intera storia di un progetto, inclusa ciascuna versione di ciascun file. Questo va bene se sono tutti sorgenti perché Git è super ottimizzato per comprimere questi dati in modo molto efficiente. Se però qualcuno in qualche momento ha aggiunto un file molto grande, ogni clone scaricherà quel file grande, anche se poi quel file è stato cancellato da una commit successiva. Poiché è raggiungibile nella cronologia, resterà sempre lì.
899
+
900
+ Questo è un grosso problema se stai convertendo a Git dei repository da Subversion o Perforce, perché in quei sistemi questo tipo di aggiunte non crea dei grandi problemi, perché non scarichi l’intera cronologia. Se hai importato i sorgenti da un altro sistema o ti rendi conto che il tuo repository è molto più grande di quello che dovrebbe, di seguito scoprirai come eliminare gli oggetti di grandi dimensioni.
901
+
902
+ Fai attenzione: questa tecnica è distruttiva per la cronologia delle tue commit. Riscrive tutte le commit a partire dal primo albero che devi modificare per rimuovere il riferimento a quel file. Se lo fai subito dopo una importazione, prima che chiunque altro inizi a lavorarci, non c’è nessun problema, altrimenti dovrai avvisare tutti i collaboratori perché ribasino il loro lavoro sulle nuove commit.
903
+
904
+ Come dimostrazioni aggiungerai un file grande nel tuo repository di test, lo rimuoverai con la commit successiva, lo cercherai e lo rimuoverai permanentemente dal repository. Prima di tutto aggiungi un file grande alla cronologia del tuo repository:
905
+
906
+ $ curl http://kernel.org/pub/software/scm/git/git-1.6.3.1.tar.bz2 > git.tbz2
907
+ $ git add git.tbz2
908
+ $ git commit -am 'added git tarball'
909
+ [master 6df7640] added git tarball
910
+ 1 files changed, 0 insertions(+), 0 deletions(-)
911
+ create mode 100644 git.tbz2
912
+
913
+ Oops: non volevi aggiungere questo archivio così grande al tuo progetto. Meglio rimediare:
914
+
915
+ $ git rm git.tbz2
916
+ rm 'git.tbz2'
917
+ $ git commit -m 'oops - removed large tarball'
918
+ [master da3f30d] oops - removed large tarball
919
+ 1 files changed, 0 insertions(+), 0 deletions(-)
920
+ delete mode 100644 git.tbz2
921
+
922
+ Esegui ora `gc` sul tuo database e guarda quanto spazio stai usando:
923
+
924
+ $ git gc
925
+ Counting objects: 21, done.
926
+ Delta compression using 2 threads.
927
+ Compressing objects: 100% (16/16), done.
928
+ Writing objects: 100% (21/21), done.
929
+ Total 21 (delta 3), reused 15 (delta 1)
930
+
931
+ Puoi eseguire anche il comando `count-objects` per vedere lo spazio che stai usando:
932
+
933
+ $ git count-objects -v
934
+ count: 4
935
+ size: 16
936
+ in-pack: 21
937
+ packs: 1
938
+ size-pack: 2016
939
+ prune-packable: 0
940
+ garbage: 0
941
+
942
+ Il valore di `size-pack` è la dimensione del packfiles in kilobytes e quindi stai usando 2MB mentre prima dell’ultima commit usavi circa 2K. Cancellando il file dell’ultima commit ovviamente non lo elimina dalla cronologia e ogni volta che qualcuno colmerà il repository, dovrà scaricare tutti i 2MB avere questo progettino, solamente perché hai aggiunto per errore questo file grande. Vediamo di risolverlo.
943
+
944
+ Prima di tutto devi trovare il file. In questo caso già sappiamo quale sia, ma supponiamo di non saperlo: come possiamo trovare quale file o quali file occupano tanto spazio? Se esegui `git gc` tutti gli oggetti saranno in un pacchetto e puoi trovare gli oggetti più grandi eseguendo un altro comando *plumbing*, `git verify-pack`, e ordinarli in base al terzo campo dell’output, che indica la dimensione. Puoi anche concatenarlo in *pipe* con `tail` perché siamo interessati solo agli file più grandi:
945
+
946
+ $ git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3
947
+ e3f094f522629ae358806b17daf78246c27c007b blob 1486 734 4667
948
+ 05408d195263d853f09dca71d55116663690c27c blob 12908 3478 1189
949
+ 7a9eb2fba2b1811321254ac360970fc169ba2330 blob 2056716 2056872 5401
950
+
951
+ L’oggetto grande è alla fine della lista: 2MB. Per scoprire di quale file si tratti useremo il comando `rev-list` che abbiamo già visto rapidamente nel Capitolo 7. Se usi l’opzione `--objects` a `rev-list`, elencherà tutti gli hash SHAs delle commit e dei blob SHAs che facciano riferimento al percorso del file. Puoi trovare il nome del blog così:
952
+
953
+ $ git rev-list --objects --all | grep 7a9eb2fb
954
+ 7a9eb2fba2b1811321254ac360970fc169ba2330 git.tbz2
955
+
956
+ Ora dobbiamo rimuovere questo file da tutti gli alberi della cronologia. Puoi vedere facilmente quali commit hanno modificato questo file:
957
+
958
+ $ git log --pretty=oneline --branches -- git.tbz2
959
+ da3f30d019005479c99eb4c3406225613985a1db oops - removed large tarball
960
+ 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 added git tarball
961
+
962
+ Ora, per rimuovere completamente questo file dalla cronologia di Git, devi riscrivere tutte le commit successive la `6df76` e per farlo useremo `filter-branch`, che hai già usato nel Capitolo 6:
963
+
964
+ $ git filter-branch --index-filter \
965
+ 'git rm --cached --ignore-unmatch git.tbz2' -- 6df7640^..
966
+ Rewrite 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 (1/2)rm 'git.tbz2'
967
+ Rewrite da3f30d019005479c99eb4c3406225613985a1db (2/2)
968
+ Ref 'refs/heads/master' was rewritten
969
+
970
+ L’opzione `--index-filter` è simile alla `--tree-filter` usata nel Capitolo 6, ad eccezione del fatto che invece di passare un comando che modifichi i file sul disco, modifichi la tua area di staging o l’indice ad ogni iterazione. Piuttosto che rimuovere un file con qualcosa simile a `rm file` dovrai rimuoverlo con `git rm --cached`, perché devi rimuoverlo dall’indice e non dal disco. Il motivo per farlo in questo modo è che è più veloce, perché Git non deve fare il checkout di ciascuna versione prima di eseguire il tuo filtro, e quindi tutto il processo è molto più veloce. Se preferisci, puoi ottenere lo stesso risultato con `--tree-filter`. L’opzione `--ignore-unmatch` di `git rm` serve a far si che non venga generato un errore se il file che stai cercando di eliminare non c’è in quella versione. Puoi, infine chiedere a `filter-branch` di riscrivere la cronologia solo a partire dalla commit `6df7640`, perché già sappiamo che è lì che ha avuto inizio il problema. Altrimenti inizierebbe dall’inizio e sarebbe inutilmente più lento.
971
+
972
+ La tua cronologia ora non ha più alcun riferimento a quel file, ma lo fanno il tuo reflog e un nuovo gruppo di riferimenti che Git ha aggiunto quando hai eseguito `filter-branch` in `.git/refs/original`, e quindi devi rimuovere anche questi e ricomprimere il database. Ma devi correggere qualsiasi cosa che ancora punti a quelle vecchie commit, prima di ricompattare il repository:
973
+
974
+ $ rm -Rf .git/refs/original
975
+ $ rm -Rf .git/logs/
976
+ $ git gc
977
+ Counting objects: 19, done.
978
+ Delta compression using 2 threads.
979
+ Compressing objects: 100% (14/14), done.
980
+ Writing objects: 100% (19/19), done.
981
+ Total 19 (delta 3), reused 16 (delta 1)
982
+
983
+ Vediamo ora quanto spazio hai recuperato.
984
+
985
+ $ git count-objects -v
986
+ count: 8
987
+ size: 2040
988
+ in-pack: 19
989
+ packs: 1
990
+ size-pack: 7
991
+ prune-packable: 0
992
+ garbage: 0
993
+
994
+ Le dimensioni del repository compresso sono ora di 7K, che è molto meglio dei 2MB precedenti. Dalle dimensioni puoi vedere che l’oggetto è ancora presente tra gli oggetti sciolti, quindi non è ancora sparito, ma non verrà più trasferito quando farai una push o se qualcun altro farà un clone, che è la cosa più importante. Se vuoi comunque eliminare definitivamente l’oggetto potrai farlo eseguendo il comando `git prune --expire`.
995
+
996
+ ## Sommario ##
997
+
998
+ A questo punto dovresti avere una discreta conoscenza di quello che Git faccia in background e anche un’infarinatura su come è implementato. Questo capitolo ha descritto alcuni comandi *plumbing*: comandi che sono più a basso livello e più semplici dei comandi *porcelain* che hai imparato nel resto del libro. Capire come funziona Git a basso livello dovrebbe renderti più facile comprendere perché sta facendo qualcosa in quel modo, ma anche permetterti di scrivere i tuoi strumenti/script per far funzionare meglio il flusso di lavoro cui sei abituato.
999
+
1000
+ Git, come filesystem indirizzabile per contenuto, è uno strumento molto potente e puoi facilmente usarlo anche per altro che non sia solo uno strumento di gestione dei sorgenti (VCS). Spero che tu possa usare la tua ritrovata conoscenza degli strumenti interni di Git per implementare una tua bellissima applicazione con questa tecnologia e trovarti a tuo agio nell’uso avanzato di Git.