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,976 @@
1
+ # Los entresijos internos de Git #
2
+
3
+ Puedes que hayas llegado a este capítulo saltando desde alguno previo o puede que hayas llegado tras leer todo el resto del libro. --En uno u otro caso, aquí es donde aprenderás acerca del funcionamiento interno y la implementación de Git--. Me parece que esta información es realmente importante para entender cúan util y potente es Git. Pero algunas personas opinan que puede ser confuso e innecesariamente complejo para novatos. Por ello, lo he puesto al final del libro; de tal forma que puedas leerlo antes o después, en cualquier momento, a lo largo de tu proceso de aprendizaje. Lo dejo en tus manos.
4
+
5
+ Y, ahora que estamos aquí, comencemos con el tema. Ante todo, por si no estuviera suficientemente claro ya, Git es fundamentalmente un sistema de archivo (filesystem) con un interface de usuario (VCS) escrito sobre él. En breve lo veremos con más detalle.
6
+
7
+ En los primeros tiempos de Git (principalmente antes de la versión 1.5), el interface de usuario era mucho más complejo, ya que se centraba en el sistema de archivos en lugar de en el VCS. En los últimos años, el IU se ha refinado hasta llegar a ser tan limpio y sencillo de usar como el de cualquier otro sistema; pero frecuentemente, el estereotipo sigue mostrando a Git como complejo y dificil de aprender.
8
+
9
+ La capa del sistema de archivos que almacena el contenido es increiblemente interesante; por ello, es lo primero que voy a desarrollar en este capítulo. A continuación mostraré los mecanismos de transporte y las tareas de mantenimiento del repositorio que posiblemente necesites usar alguna vez.
10
+
11
+ ## Fontaneria y porcelana ##
12
+
13
+ Este libro habla acerca de como utilizar Git con más o menos 30 verbos, tales como 'checkout', 'branch', 'remote', etc. Pero, debido al origen de Git como una caja de herramientas para un VCS en lugar de como un completo y amigable sistema VCS, existen unos cuantos verbos para realizar tareas de bajo nivel y que se diseñaron para poder ser utilizados de forma encadenada al estilo UNIX o para ser utilizados en scripts. Estos comandos son conocidos como los "comandos de fontanería", mientras que los comandos más amigables son conocidos como los "comandos de porcelana".
14
+
15
+ Los primeros ocho capítulos de este libro se encargan casi exclusivamente de los comandos de porcelana. Pero en este capítulo trataremos sobre todo con los comandos de fontaneria; comandos que te darán acceso a los entresijos internos de Git y que te ayudarán a comprender cómo y por qué hace Git lo que hace como lo hace. Estos comando no están pensados para ser utilizados manualmente desde la línea de comandos; sino más bien para ser utilizados como bloques de construcción para nuevas herramientas y scripts de usuario personalizados.
16
+
17
+ Cuando lanzas 'git init' sobre una carpeta nueva o sobre una ya existente, Git crea la carpeta auxiliar '.git'; la carpeta donde se ubica prácticamente todo lo almacenado y manipulado por Git. Si deseas hacer una copia de seguridad de tu repositorio, con tan solo copiar esta carpeta a cualquier otro lugar ya tienes tu copia completa. Todo este capítulo se encarga de repasar el contenido en dicha carpeta. Tiene un aspecto como este:
18
+
19
+ $ ls
20
+ HEAD
21
+ branches/
22
+ config
23
+ description
24
+ hooks/
25
+ index
26
+ info/
27
+ objects/
28
+ refs/
29
+
30
+ Puede que veas algunos otros archivos en tu carpeta '.git', pero este es el contenido de un repositorio recién creado tras ejecutar 'git init', --es la estructura por defecto--. La carpeta 'branches' no se utiliza en las últimas versiones de Git, y el archivo 'description' se utiliza solo en el programa GitWeb; por lo que no necesitas preocuparte por ellos. El archivo 'config' contiene las opciones de configuración específicas de este proyecto concreto, y la carpeta 'info' guarda un archivo global de exclusión con los patrones a ignorar ademas de los presentes en el archivo .gitignore. La carpeta 'hooks' contiene tus scripts, tanto de la parte cliente como de la parte servidor, tal y como se ha visto a detalle en el capítulo 6.
31
+
32
+ Esto nos deja con cuatro entradas importantes: los archivos 'HEAD' e 'index' y las carpetas 'objects' y 'refs'. Estos elementos forman el núcleo de Git. La carpeta 'objects' guarda el contenido de tu base de datos, la carpeta 'refs' guarda los apuntadores a las confirmaciones de cambios (commits), el archivo 'HEAD' apunta a la rama que tengas activa (checked out) en este momento, y el archivo 'index' es donde Git almacena la información sobre tu area de preparación (staging area). Vamos a mirar en detalle cada una de esas secciones, para ver cómo trabaja Git.
33
+
34
+ ## Los objetos Git ##
35
+
36
+ Git es un sistema de archivo orientado a contenidos. Estupendo. Y eso, ¿qué significa?
37
+ Pues significa que el núcleo Git es un simple almacén de claves y valores. Cuando insertas cualquier tipo de contenido, él te devuelve una clave que puedes utilizar para recuperar de nuevo dicho contenido en cualquier momento. Para verlo en acción, puedes utilizar el comando de fontanería 'hash-object'. Este comando coge ciertos datos, los guarda en la carpeta '.git.' y te devuelve la clave bajo la cual se han guardado. Para empezar, inicializa un nuevo repositorio Git y comprueba que la carpeta 'objects' está vacia.
38
+
39
+ $ mkdir test
40
+ $ cd test
41
+ $ git init
42
+ Initialized empty Git repository in /tmp/test/.git/
43
+ $ find .git/objects
44
+ .git/objects
45
+ .git/objects/info
46
+ .git/objects/pack
47
+ $ find .git/objects -type f
48
+ $
49
+
50
+ Git ha inicializado la carpeta 'objects', creando en ella las subcarpetas 'pack' e 'info'; pero aún no hay archivos en ellas. Luego, guarda algo de texto en la base de datos de Git:
51
+
52
+ $ echo 'test content' | git hash-object -w --stdin
53
+ d670460b4b4aece5915caf5c68d12f560a9fe3e4
54
+
55
+ La opción '-w' indica a 'hash-object' que ha de guardar el objeto; de otro modo, el comando solo te respondería cual sería su clave. La opción '--stdin' indica al comando de leer desde la entrada estandar stdin; si no lo indicas, 'hash-object' espera encontrar la ubicación de un archivo. La salida del comando es una suma de comprobación (checksum hash) de 40 caracteres. Este checksum hash SHA-1 es una suma de comprobación del contenido que estás guardando más una cabecera; cabecera sobre la que trataremos en breve. En estos momentos, ya puedes comprobar la forma en que Git ha guardado tus datos:
56
+
57
+ $ find .git/objects -type f
58
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
59
+
60
+ Como puedes ver, hay un archivo en la carpeta 'objects'. En principio, esta es la forma en que guarda Git los contenidos; como un archivo por cada pieza de contenido, nombrado con la suma de comprobación SHA-1 del contenido y su cabecera. La subcarpeta se nombra con los primeros 2 caracteres del SHA, y el archivo con los restantes 38 caracteres.
61
+
62
+ Puedes volver a recuperar los contenidos usando el comando 'cat-file'. Este comando es algo así como una "navaja suiza" para inspeccionar objetos Git. Pasandole la opción '-p', puedes indicar al comando 'cat-file' que deduzca el tipo de contenido y te lo muestre adecuadamente:
63
+
64
+ $ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
65
+ test content
66
+
67
+ Ahora que sabes cómo añadir contenido a Git y cómo recuperarlo de vuelta. Lo puedes hacer también con el propio contenido de los archivos. Por ejemplo, puedes realizar un control simple de versiones sobre un archivo. Para ello, crea un archivo nuevo y guarda su contenido en tu base de datos:
68
+
69
+ $ echo 'version 1' > test.txt
70
+ $ git hash-object -w test.txt
71
+ 83baae61804e65cc73a7201a7252750c76066a30
72
+
73
+ A continuación, escribe algo más de contenido en el archivo y vuelvelo a guardar:
74
+
75
+ $ echo 'version 2' > test.txt
76
+ $ git hash-object -w test.txt
77
+ 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
78
+
79
+ Tu base de datos contendrá las dos nuevas versiones del archivo, así como el primer contenido que habias guardado en ella antes:
80
+
81
+ $ find .git/objects -type f
82
+ .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
83
+ .git/objects/83/baae61804e65cc73a7201a7252750c76066a30
84
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
85
+
86
+ Podrás revertir el archivo a su primera versión:
87
+
88
+ $ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt
89
+ $ cat test.txt
90
+ version 1
91
+
92
+ o a su segunda versión
93
+
94
+ $ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt
95
+ $ cat test.txt
96
+ version 2
97
+
98
+ Pero no es práctico esto de andar recordando la clave SHA-1 para cada versión de tu archivo; es más, realmente no estás guardando el nombre de tu archivo en el sistema, --solo su contenido--. Este tipo de objeto se denomina un blob (binary large object). Con la orden 'cat-file -t' puedes comprobar el tipo de cualquier objeto almacenado en Git, sin mas que indicar su clave SHA-1':
99
+
100
+ $ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
101
+ blob
102
+
103
+ ### Objetos tipo arbol ###
104
+
105
+ El siguiente tipo de objeto a revisar serán los objetos tipo arbol. Estos se encargan de resolver el problema de guardar un nombre de archivo, a la par que guardamos conjuntamente un grupo de archivos. Git guarda contenido de manera similar a un sistema de archivos UNIX, pero de forma algo más simple. Todo el contenido se guarda como objetos arbol (tree) u objetos binarios (blob). Correspondiendo los árboles a las entradas de carpetas; y correspondiendo los binarios, mas o menos, a los contenidos de los archivos (inodes). Un objeto tipo árbol tiene una o más entradas de tipo arbol. Y cada una de ellas consta de un puntero SHA-1 a un objeto binario (blob) o a un subárbol, más sus correspondientes datos de modo, tipo y nombre de archivo. Por ejemplo, el árbol que hemos utilizado recientemente en el proyecto simplegit, puede resultar algo así como:
106
+
107
+ $ git cat-file -p master^{tree}
108
+ 100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
109
+ 100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
110
+ 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
111
+
112
+ La sentencia `master^{tree}` indica el objeto árbol apuntado por la última confirmación de cambios (commit) en tu rama principal (master). Fíjate en que la carpeta `lib` no es un objeto binario, sino un apuntador a otro objeto tipo árbol.
113
+
114
+ $ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
115
+ 100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb
116
+
117
+ Conceptualmente, la información almacenada por Git es algo similar a la Figura 9-1.
118
+
119
+ Insert 18333fig0901.png
120
+ Figura 9-1. Versión simplificada del modelo de datos de Git.
121
+
122
+ Puedes crear tu propio árbol. Habitualmente Git suele crear un árbol a partir del estado de tu área de preparación (staging area) o índice, escribiendo un objeto árbol con él. Por tanto, para crear un objeto árbol, previamente has de crear un índice preparando algunos archivos para ser almacenados. Puedes utilizar el comando de "fontaneria" `update-index` para crear un índice con una sola entrada, --la primera version de tu archivo text.txt--. Este comando se utiliza para añadir artificialmente la versión anterior del archivo test.txt. a una nueva área de preparación Has de utilizar la opción `--add`, porque el archivo no existe aún en tu área de preparación (es más, ni siquiera tienes un área de preparación). Y has de utilizar también la opción `--cacheinfo`, porque el archivo que estas añadiendo no está en tu carpeta, sino en tu base de datos. Para terminar, has de indicar el modo, la clave SHA-1 y el nombre de archivo:
123
+
124
+ $ git update-index --add --cacheinfo 100644 \
125
+ 83baae61804e65cc73a7201a7252750c76066a30 test.txt
126
+
127
+ En este caso, indicas un modo `100644`, el modo que denota un archivo normal. Otras opciones son `100755`, para un achivo ejecutable; o `120000`, para un enlace simbólico. Estos modos son como los modos de UNIX, pero mucho menos flexibles. Solo estos tres modos son válidos para archivos (blobs) en Git; (aunque también se permiten otros modos para carpetas y submódulos).
128
+
129
+ Tras esto, puedes usar el comando `write-tree` para escribir el área de preparacón a un objeto tipo árbol. Sin necesidad de la opción `-w`, solo llamando al comando `write-tree`, y si dicho árbol no existiera ya, se crea automáticamente un objeto tipo árbol a partir del estado del índice.
130
+
131
+ $ git write-tree
132
+ d8329fc1cc938780ffdd9f94e0d364e0ea74f579
133
+ $ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
134
+ 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt
135
+
136
+ También puedes comprobar si realmente es un objeto tipo árbol:
137
+
138
+ $ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
139
+ tree
140
+
141
+ Vamos a crear un nuevo árbol con la segunda versión del archivo test.txt y con un nuevo archivo.
142
+
143
+ $ echo 'new file' > new.txt
144
+ $ git update-index test.txt
145
+ $ git update-index --add new.txt
146
+
147
+ El área de preparación contendrá ahora la nueva versión de test.txt, así como el nuevo archivo new.txt. Escribiendo este árbol, (guardando el estado del área de preparación o índice), podrás ver que aparece algo así como:
148
+
149
+ $ git write-tree
150
+ 0155eb4229851634a0f03eb265b69f5a2d56f341
151
+ $ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341
152
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
153
+ 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
154
+
155
+ Aquí se vén las entradas para los dos archivos y también el que la suma de comprobación SHA-1 de test.txt es la "segunda versión" de la anterior (`1f7a7a`). Simplemente por diversión, puedes añadir el primer árbol como una subcarpeta de este otro. Para leer árboles al área de preparación puedes utilizar el comando `read-tree`. Y, en este caso, puedes hacerlo como si fuera una subcarpeta utilizando la opción `--prefix`:
156
+
157
+ $ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579
158
+ $ git write-tree
159
+ 3c4e9cd789d88d8d89c1073707c3585e41b0e614
160
+ $ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614
161
+ 040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 bak
162
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
163
+ 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt
164
+
165
+ Si crearas una carpeta de trabajo a partir de este nuevo árbol que acabas de escribir, obtendrías los dos archivos en el nivel principal de la carpeta de trabajo y una subcarpeta llamada `bak` conteniendo la primera versión del archivo test.txt. Puedes pensar en algo parecido a la Figura 9-2 para representar los datos guardados por Git para estas estructuras.
166
+
167
+ Insert 18333fig0902.png
168
+ Figura 9-2. La estructura del contenido Git para tus datos actuales.
169
+
170
+ ### Objetos de confirmación de cambios ###
171
+
172
+ Tienes tres árboldes que representan diferentes momentos interesantes de tu proyecto, pero el problema principal sigue siendo el estar obligado a recordar los tres valores SHA-1 para poder recuperar cualquiera de esos momentos. Asimismo, careces de información alguna sobre quién guardó las instantáneas de esos momentos, cuándo fueron guardados o por qué se guardaron. Este es el tipo de información que almacenan para tí los objetos de confirmación de cambios.
173
+
174
+ Para crearlos, tan solo has de llamar al comando `commit-tree`, indicando uno de los árboles SHA-1 y los objetos de confirmación de cambios que lo preceden (si es que lo precede alguno). Empezando por el primer árbol que has escrito:
175
+
176
+ $ echo 'first commit' | git commit-tree d8329f
177
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d
178
+
179
+ Con el comando `cat-file` puedes revisar el nuevo objeto de confirmación de cambios recién creado:
180
+
181
+ $ git cat-file -p fdf4fc3
182
+ tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
183
+ author Scott Chacon <schacon@gmail.com> 1243040974 -0700
184
+ committer Scott Chacon <schacon@gmail.com> 1243040974 -0700
185
+
186
+ first commit
187
+
188
+ El formato para un objeto de confirmación de cambios (commit) es sencillo, contemplando: el objeto tipo árbol para la situación del proyecto en ese momento puntual; la información sobre el autor/confirmador, recogida desde las opciones de configuración`user.name` y `user.email`; la fecha y hora actuales; una línea en blanco; y el mensaje de la confirmación de cambios.
189
+
190
+ Puedes seguir adelante, escribiendo los otros dos objetos de confirmación de cambios. Y relacionando cada uno de ellos con su inmediato anterior:
191
+
192
+ $ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
193
+ cac0cab538b970a37ea1e769cbbde608743bc96d
194
+ $ echo 'third commit' | git commit-tree 3c4e9c -p cac0cab
195
+ 1a410efbd13591db07496601ebc7a059dd55cfe9
196
+
197
+ Cada uno de estos tres objetos de confirmación de cambios apunta a uno de los tres objetos tipo árbol que habias creado previamente. Más aún, en estos momentos tienes ya un verdadero historial Git. Lo puedes comprobar con el comando `git log`. Lanzandolo mientras estás en la última de las confirmaciones de cambio.
198
+
199
+ $ git log --stat 1a410e commit 1a410efbd13591db07496601ebc7a059dd55cfe9
200
+ Author: Scott Chacon <schacon@gmail.com>
201
+ Date: Fri May 22 18:15:24 2009 -0700
202
+
203
+ third commit
204
+
205
+ bak/test.txt | 1 +
206
+ 1 files changed, 1 insertions(+), 0 deletions(-)
207
+
208
+ commit cac0cab538b970a37ea1e769cbbde608743bc96d
209
+ Author: Scott Chacon <schacon@gmail.com>
210
+ Date: Fri May 22 18:14:29 2009 -0700
211
+
212
+ second commit
213
+
214
+ new.txt | 1 +
215
+ test.txt | 2 +-
216
+ 2 files changed, 2 insertions(+), 1 deletions(-)
217
+
218
+ commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d
219
+ Author: Scott Chacon <schacon@gmail.com>
220
+ Date: Fri May 22 18:09:34 2009 -0700
221
+
222
+ first commit
223
+
224
+ test.txt | 1 +
225
+ 1 files changed, 1 insertions(+), 0 deletions(-)
226
+
227
+ ¡Sorprendente!. Acabas de confeccionar un historial Git utilizando solamente operaciones de bajo nivel, sin usar ninguno de los interfaces principales. Esto es básicamente lo que hace Git cada vez que utilizas los comandos `git add` y `git commit`: guardar objetos binarios (blobs) para los archivos modificados, actualizar el índice, escribir árboles (trees), escribir objetos de confirmación de cambios (commits) que los referencian y relacionar cada uno de ellos con su inmediato precedente. Estos tres objetos Git, -binario, árbol y confirmación de cambios--, se guardan como archivos separados en la carpeta `.git/objects`. Aquí se muestran todos los objetos presentes en este momento en la carpeta del ejemplo, con comentarios acerca de lo que almacena cada uno de ellos:
228
+
229
+ $ find .git/objects -type f
230
+ .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
231
+ .git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
232
+ .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
233
+ .git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
234
+ .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
235
+ .git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
236
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
237
+ .git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
238
+ .git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
239
+ .git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
240
+
241
+ Siguiendo todos los enlaces internos, puedes llegar a un gráfico similar al de la figura 9-3.
242
+
243
+ Insert 18333fig0903.png
244
+ Figura 9-3. Todos los objetos en tu carpeta Git.
245
+
246
+ ### Almacenamiento de los objetos ###
247
+
248
+ He citado anteriormente que siempre se almacena una cabecera junto al contenido. Vamos a hechar un vistazo a cómo Git almacena sus objetos. Te mostraré el proceso de guardar un objeto binario grande (blob), --en este caso la cadena de texto "what is up, doc?" (¿qué hay de nuevo, viejo?)--, interactivamente, en el lenguaje de script Ruby. Puedes arrancar el modo interactivo de Ruby con el comando `irb`:
249
+
250
+ $ irb
251
+ >> content = "what is up, doc?"
252
+ => "what is up, doc?"
253
+
254
+ Git construye la cabecera comenzando por el tipo de objeto, en este caso un objeto binario grande (blob). Después añade un espacio, seguido del tamaño del contenido y termina con un byte nulo:
255
+
256
+ >> header = "blob #{content.length}\0"
257
+ => "blob 16\000"
258
+
259
+ Git concatena la cabecera y el contenido original, para calcular la suma de control SHA-1 conjunta. En Ruby, para calcular el valor SHA-1 de una cadena de texto: has de incluir la libreria de generación SHA1 con el comando `require` y llamar luego a la orden `Digest::SHA1.hexdigest()`:
260
+
261
+ >> store = header + content
262
+ => "blob 16\000what is up, doc?"
263
+ >> require 'digest/sha1'
264
+ => true
265
+ >> sha1 = Digest::SHA1.hexdigest(store)
266
+ => "bd9dbf5aae1a3862dd1526723246b20206e5fc37"
267
+
268
+ Git comprime todo el contenido con zlib. Y tu puedes hacer lo mismo en Ruby con la libreria zlib. Primero has de incluir la libreria y luego lanzar la orden `Zlib::Deflate.deflate()` sobre el contenido:
269
+
270
+ >> require 'zlib'
271
+ => true
272
+ >> zlib_content = Zlib::Deflate.deflate(store)
273
+ => "x\234K\312\311OR04c(\317H,Q\310,V(-\320QH\311O\266\a\000_\034\a\235"
274
+
275
+ Para terminar, has de escribir el contenido comprimido en un objeto en disco. Para fijar el lugar donde almacenarlo, utilizaremos como nombre de carpeta los dos primeros caracteres del valor SHA-1 y como nombre de archivo los restantes 38 caracteres de dicho valor SHA-1. En Ruby, puedes utilizar la función `FileUtils.mkdir_p()` para crear una carpeta. Después, puedes abrir un archivo con la orden `File.open()` y escribir contenido en él con la orden `write()`:
276
+
277
+ >> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
278
+ => ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"
279
+ >> require 'fileutils'
280
+ => true
281
+ >> FileUtils.mkdir_p(File.dirname(path))
282
+ => ".git/objects/bd"
283
+ >> File.open(path, 'w') { |f| f.write zlib_content }
284
+ => 32
285
+
286
+ Y ¡esto es todo!. --acabas de crear un auténtico objeto Git binario grande (blob)--. Todos los demas objetos Git se almacenan de forma similar, pero con la diferencia de que sus cabeceras comienzan con un tipo diferente. En lugar de 'blob' (objeto binario grande), comenzarán por 'commit' (confirmación de cambios), o por 'tree' (árbol). Además, el contenido de un binario (blob) puede ser prácticamente cualquier cosa. Mientras que el contenido de una confirmación de cambios (commit) o de un árbol (tree) han de seguir unos formatos internos muy concretos.
287
+
288
+ ## Referencias Git ##
289
+
290
+ Puedes utilizar algo así como `git log 1a410e` para hechar un vistazo a lo largo de toda tu historia, recorriendola y encontrando todos tus objetos. Pero para ello has necesitado recordar que la última confirmación de cambios es `1a410e`. Necesitarias un archivo donde almacenar los valores de las sumas de comprobación SHA-1, junto con sus respectivos nombres simples que puedas utilizar como enlaces en lugar de la propia suma de comprobación.
291
+
292
+ En Git, estp es lo que se conoce como "referencias" o "refs". En la carpeta `.git/refs` puedes encontrar esos archivos con valores SHA-1 y nombres . En el proyecto actual, la carpeta aún no contiene archivos, pero sí contiene una estructura simple:
293
+
294
+ $ find .git/refs
295
+ .git/refs
296
+ .git/refs/heads
297
+ .git/refs/tags
298
+ $ find .git/refs -type f
299
+ $
300
+
301
+ Para crear una nueva referencia que te sirva de ayuda para recordar cual es tu última confirmación de cambios, puedes realizar técnicamente algo tan simple como:
302
+
303
+ $ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master
304
+
305
+ A partir de ese momento, puedes utilizar esa referencia principal que acabas de crear, en lugar del valor SHA-1, en todos tus comandos:
306
+
307
+ $ git log --pretty=oneline master
308
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
309
+ cac0cab538b970a37ea1e769cbbde608743bc96d second commit
310
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
311
+
312
+ No es conveniente editar directamente los archivos de referencia. Git suministra un comando mucho más seguro para hacer esto. Si necesitas actualizar una referencia, puedes utilizar el comando `update-ref`:
313
+
314
+ $ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
315
+
316
+ Esto es lo que es básicamente una rama en Git: un simple apuntador o referencia a la cabeza de una línea de trabajo. Para crear una rama hacia la segunda confirmación de cambios, puedes hacer:
317
+
318
+ $ git update-ref refs/heads/test cac0ca
319
+
320
+ Y la rama contendrá únicamente trabajo desde esa confirmación de cambios hacia atrás.
321
+
322
+ $ git log --pretty=oneline test
323
+ cac0cab538b970a37ea1e769cbbde608743bc96d second commit
324
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
325
+
326
+ En estos momentos, tu base de datos Git se parecerá conceptualmente a la figura 9-4.
327
+
328
+ Insert 18333fig0904.png
329
+ Figura 9-4. Objetos en la carpeta Git, con referencias a las cabeceras de las ramas.
330
+
331
+ Cuando lanzas comandos como `git branch (nombrederama)`. Lo que hace Git es añadir, a cualquier nueva referencia que vayas a crear, el valor SHA-1 de la última confirmación de cambios en esa rama.
332
+
333
+ ### La CABEZA (HEAD) ###
334
+
335
+ Y ahora nos preguntamos, al lanzar el comando `git branch (nombrederama)`, ¿cómo sabe Git cuál es el valor SHA-1 de la última confirmación de cambios?. La respuesta a esta pregunta es el archivo HEAD (CABEZA). El archivo HEAD es una referencia simbólica a la rama donde te encuentras en cada momento. Por referencia simbólica me refiero a que, a diferencia de una referencia normal, esta contiene un enlace a otra referencia en lugar de un valor SHA-1. Si miras dentro del archivo, podrás observar algo como:
336
+
337
+ $ cat .git/HEAD
338
+ ref: refs/heads/master
339
+
340
+ Si lanzas el comando `git checkout test`, Git actualiza el contenido del archivo:
341
+
342
+ $ cat .git/HEAD
343
+ ref: refs/heads/test
344
+
345
+ Cuando lanzas una orden `git commit`, se crea un nuevo objeto de confirmación de cambios teniendo como padre la confirmación con valor SHA-1 a la que en ese momento esté apuntando la referencia en HEAD.
346
+
347
+ Puedes editar manualmente este archivo. Pero, también para esta tarea existe un comando más seguro: `symbolic-ref`. Puedes leer el valor de HEAD a través de él:
348
+
349
+ $ git symbolic-ref HEAD
350
+ refs/heads/master
351
+
352
+ Y también puedes cambiar el valor de HEAD a través de él:
353
+
354
+ $ git symbolic-ref HEAD refs/heads/test
355
+ $ cat .git/HEAD
356
+ ref: refs/heads/test
357
+
358
+ Pero no puedes fijar una referencia simbólica fuera de "refs":
359
+
360
+ $ git symbolic-ref HEAD test
361
+ fatal: Refusing to point HEAD outside of refs/
362
+
363
+ ### Etiquetas ###
364
+
365
+ Acabas de conocer los tres principales tipos de objetos Git, pero hay un cuarto. El objeto tipo etiqueta es muy parecido al tipo confirmación de cambios, --contiene un marcador, una fecha, un mensaje y un enlace--. Su principal diferencia reside en que apunta a una confirmación de cambios (commit) en lugar de a un árbol (tree). Es como una referencia a una rama, pero permaneciendo siempre inmovil, --apuntando siempre a la misma confirmación de cambios--, dándo un nombre mas amigable a esta.
366
+
367
+ Tal y como se ha comentado en el capítulo 2, hay dos tipos de etiquetas: las anotativas y las ligeras. Puedes crear una etiqueta ligera lanzando un comando tal como:
368
+
369
+ $ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
370
+
371
+ Una etiqueta ligera es simplemente eso: una rama que nunca se mueve. Sin embargo, una etiqueta anotativa es más compleja. Al crear una etiqueta anotativa, Git crea un objeto tipo etiqueta y luego escribe una referencia apuntando a él en lugar de apuntar directamente a una confirmación de cambios. Puedes comprobarlo creando una: (la opción `-a` indica que la etiqueta es anotativa)
372
+
373
+ $ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 –m 'test tag'
374
+
375
+ Este es el objeto SHA-1 creado:
376
+
377
+ $ cat .git/refs/tags/v1.1
378
+ 9585191f37f7b0fb9444f35a9bf50de191beadc2
379
+
380
+ Ahora, lanzando el comando `cat-file` para ese valor SHA-1:
381
+
382
+ $ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
383
+ object 1a410efbd13591db07496601ebc7a059dd55cfe9
384
+ type commit
385
+ tag v1.1
386
+ tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
387
+
388
+ test tag
389
+
390
+ Merece destacar que el inicio del objeto apunta al SHA-1 de la confirmación de cambios recién etiquetada. Y también el que no ha sido necesario apuntar directamente a una confirmación de cambios. Realmente puedes etiquetar cualquier tipo de objeto Git. Por ejemplo, en el código fuente de Git los gestores han añadido su clave GPG pública como un objeto binario (blob) y lo han etiquetado. Puedes ver esta clave pública con el comando
391
+
392
+ $ git cat-file blob junio-gpg-pub
393
+
394
+ lanzado sobre el código fuente de Git. El kernel de Linux tiene también un objeto tipo etiqueta apuntando a un objeto que no es una confirmación de cambios (commit). La primera etiqueta que se creó es la que apunta al árbol (tree) inicial donde se importó el código fuente.
395
+
396
+ ### Remotos ###
397
+
398
+ El tercer tipo de referencia que puedes observar es la referencia remota. Si añades un remoto y envias algo a él, Git almacenará en dicho remoto el último valor para cada rama presente en la carpeta `refs/remotes`. Por ejemplo, puedes añadir un remoto denominado `origin` y enviar a él tu rama `master`:
399
+
400
+ $ git remote add origin git@github.com:schacon/simplegit-progit.git
401
+ $ git push origin master
402
+ Counting objects: 11, done.
403
+ Compressing objects: 100% (5/5), done.
404
+ Writing objects: 100% (7/7), 716 bytes, done.
405
+ Total 7 (delta 2), reused 4 (delta 1)
406
+ To git@github.com:schacon/simplegit-progit.git
407
+ a11bef0..ca82a6d master -> master
408
+
409
+ Tras lo cual puedes confirmar cual era la rama `master` en el remoto `origin` la última vez que comunicase con el servidor. Comprobando el archivo `refs/remotes/origin/master`:
410
+
411
+ $ cat .git/refs/remotes/origin/master
412
+ ca82a6dff817ec66f44342007202690a93763949
413
+
414
+ Las referencias remotas son distintas de las ramas normales, (referencias en `refs/heads`); y no se pueden recuperar (checkout) al espacio de trabajo. Git las utiliza solamente como marcadores al último estado conocido de cada rama en cada servidor remoto declarado.
415
+
416
+ ## Archivos empaquetadores ##
417
+
418
+ Volviendo a los objetos en la base de datos de tu repositorio Git de pruebas. En este momento, tienes 11 objetos --4 binarios, 3 árboles, 3 confirmaciones de cambios y 1 etiqueta--.
419
+
420
+ $ find .git/objects -type f
421
+ .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2
422
+ .git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3
423
+ .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2
424
+ .git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3
425
+ .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1
426
+ .git/objects/95/85191f37f7b0fb9444f35a9bf50de191beadc2 # tag
427
+ .git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2
428
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 'test content'
429
+ .git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1
430
+ .git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt
431
+ .git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1
432
+
433
+ Git comprime todos esos archivos con zlib, por lo que ocupan más bien poco. Entre todos suponen solamente 925 bytes. Puedes añadir algún otro archivo de gran contenido al repositorio. Y verás una interesante funcionalidad de Git. Añadiendo el archivo repo.rb de la libreria Grit con la que has estado trabajando anteriormente, supondrá añadir un achivo con unos 12 Kbytes de código fuente.
434
+
435
+ $ curl http://github.com/mojombo/grit/raw/master/lib/grit/repo.rb > repo.rb
436
+ $ git add repo.rb
437
+ $ git commit -m 'added repo.rb'
438
+ [master 484a592] added repo.rb
439
+ 3 files changed, 459 insertions(+), 2 deletions(-)
440
+ delete mode 100644 bak/test.txt
441
+ create mode 100644 repo.rb
442
+ rewrite test.txt (100%)
443
+
444
+ Si hechas un vistazo al árbol resultante, podrás observar el valor SHA-1 del objeto binario correspondiente a dicho archivo repo.rb:
445
+
446
+ $ git cat-file -p master^{tree}
447
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
448
+ 100644 blob 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e repo.rb
449
+ 100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
450
+
451
+ Y ver su tamaño con el comando `git cat-file`:
452
+
453
+ $ git cat-file -s 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e
454
+ 12898
455
+
456
+ Ahora, modifica un poco dicho archivo y comprueba lo que sucede:
457
+
458
+ $ echo '# testing' >> repo.rb
459
+ $ git commit -am 'modified repo a bit'
460
+ [master ab1afef] modified repo a bit
461
+ 1 files changed, 1 insertions(+), 0 deletions(-)
462
+
463
+ Revisando el árbol creado por esta última confirmación de cambios, verás algo interesante:
464
+
465
+ $ git cat-file -p master^{tree}
466
+ 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt
467
+ 100644 blob 05408d195263d853f09dca71d55116663690c27c repo.rb
468
+ 100644 blob e3f094f522629ae358806b17daf78246c27c007b test.txt
469
+
470
+ El objeto binario es ahora un binario completamente diferente. Aunque solo has añadido una única línea al final de un archivo que ya contenia 400 líneas, Git ha almacenado el resultado como un objeto completamente nuevo.
471
+
472
+ $ git cat-file -s 05408d195263d853f09dca71d55116663690c27c
473
+ 12908
474
+
475
+ Y, así, tienes en tu disco dos objetos de 12 Kbytes prácticamente idénticos. ¿No seria práctico si Git pudiera almacenar uno de ellos completo y luego solo las diferencias del segundo con respecto al primero?
476
+
477
+ Pues bien, Git lo puede hacer. El formato inicial como Git guarda sus objetos en disco es el formato conocido como "relajado" (loose). Pero, sin embargo, de vez en cuando, Git suele agrupar varios de esos objetos en un único binario denominado archivo "empaquetador". Para ahorrar espacio y hacer así más eficiente su almacenamiento. Esto sucede cada vez que tiene demasiados objetos en formato "relajado"; o cuando tu invocas manualmente al comando `git gc`; o justo antes de enviar cualquier cosa a un servidor remoto. Puedes comprobar el proceso pidiendole expresamente a Git que empaquete objetos, utilizando el comando `git gc`:
478
+
479
+ $ git gc
480
+ Counting objects: 17, done.
481
+ Delta compression using 2 threads.
482
+ Compressing objects: 100% (13/13), done.
483
+ Writing objects: 100% (17/17), done.
484
+ Total 17 (delta 1), reused 10 (delta 0)
485
+
486
+ Tras esto, si miras los objetos presentes en la carpeta, veras que han desaparecido la mayoria de los que habia anteriormente. Apareciendo un par de objetos nuevos:
487
+
488
+ $ find .git/objects -type f
489
+ .git/objects/71/08f7ecb345ee9d0084193f147cdad4d2998293
490
+ .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
491
+ .git/objects/info/packs
492
+ .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx
493
+ .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack
494
+
495
+ Solo han quedado aquellos objetos binarios no referenciados por ninguna confirmación de cambios --en este caso, el ejemplo de "¿que hay de nuevo, viejo?" y el ejemplo de "contenido de pruebas"-- Porque nunca los has llegado a incluir en ninguna confirmación de cambios, no se han considerado como objetos definitivos y, por tanto, no han sido empaquetados.
496
+
497
+ Los otros archivos presentes son el nuevo archivo empaquetador y un índice. El archivo empaquetador es un único archivo conteniendo dentro de él todos los objetos sueltos eliminados del sistema de archivo. El índice es un archivo que contiene las posiciones de cada uno de esos objetos dentro del archivo empaquetador. Permitiendonos así buscarlos y extraer rápidamente cualquiera de ellos. Lo que es interesante es el hecho de que, aunque los objetos originales presentes en el disco antes del `gc` ocupaban unos 12 Kbytes, el nuevo archivo empaquetador apenas ocupa 6 Kbytes. Empaquetando los objetos, has conseguido reducir a la mitad el uso de disco.
498
+
499
+ ¿Cómo consigue Git esto? Cuando Git empaqueta objetos, va buscando archivos de igual nombre y tamaño similar. Almacenando únicamente las diferencias entre una versión de cada archivo y la siguiente. Puedes comprobarlo mirando en el interior del archivo empaquetador. Y, para eso, has de utilizar el comando "de fontaneria" `git verify-pack`:
500
+
501
+ $ git verify-pack -v \
502
+ .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx
503
+ 0155eb4229851634a0f03eb265b69f5a2d56f341 tree 71 76 5400
504
+ 05408d195263d853f09dca71d55116663690c27c blob 12908 3478 874
505
+ 09f01cea547666f58d6a8d809583841a7c6f0130 tree 106 107 5086
506
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 commit 225 151 322
507
+ 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob 10 19 5381
508
+ 3c4e9cd789d88d8d89c1073707c3585e41b0e614 tree 101 105 5211
509
+ 484a59275031909e19aadb7c92262719cfcdf19a commit 226 153 169
510
+ 83baae61804e65cc73a7201a7252750c76066a30 blob 10 19 5362
511
+ 9585191f37f7b0fb9444f35a9bf50de191beadc2 tag 136 127 5476
512
+ 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e blob 7 18 5193 1 \
513
+ 05408d195263d853f09dca71d55116663690c27c
514
+ ab1afef80fac8e34258ff41fc1b867c702daa24b commit 232 157 12
515
+ cac0cab538b970a37ea1e769cbbde608743bc96d commit 226 154 473
516
+ d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree 36 46 5316
517
+ e3f094f522629ae358806b17daf78246c27c007b blob 1486 734 4352
518
+ f8f51d7d8a1760462eca26eebafde32087499533 tree 106 107 749
519
+ fa49b077972391ad58037050f2a75f74e3671e92 blob 9 18 856
520
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d commit 177 122 627
521
+ chain length = 1: 1 object
522
+ pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.pack: ok
523
+
524
+ Puedes observar que el objeto binario `9bc1d`, (correspondiente a la primera versión de tu archivo repo.rb), tiene una referencia al binario `05408` (la segunda versión de ese archivo). La tercera columna refleja el tamaño de cada objeto dentro del paquete. Observandose que `05408` ocupa unos 12 Kbytes; pero `9bc1d` solo ocupa 7 bytes. Resulta curioso que se almacene completa la segunda versión del archivo, mientras que la versión original es donde se almacena solo la diferencia. Esto se debe a la mayor probabilidad de que vayamos a recuperar rápidamente la versión mas reciente del archivo.
525
+
526
+ Lo verdaderamente interesante de todo este proceso es que podemos reempaquetar en cualquier momento De vez en cuando, Git, en su empeño por optimizar la ocupación de espacio, reempaqueta automaticamente toda la base de datos Pero, también tu mismo puedes reempaquetar en cualquier momento, lanzando manualmente el comando `git gc`.
527
+
528
+ ## Las especificaciones para hacer referencia a... (refspec) ##
529
+
530
+ A lo largo del libro has utilizado sencillos mapeados entre ramas remotas y referencias locales; pero las cosas pueden ser bastante más complejas.
531
+ Supón que añades un remoto tal que:
532
+
533
+ $ git remote add origin git@github.com:schacon/simplegit-progit.git
534
+
535
+ Esto añade una nueva sección a tu archivo `.git/config`, indicando el nombre del remoto (`origin`), la ubicación (URL) del repositorio remoto y la referencia para recuperar (fench) desde él:
536
+
537
+ [remote "origin"]
538
+ url = git@github.com:schacon/simplegit-progit.git
539
+ fetch = +refs/heads/*:refs/remotes/origin/*
540
+
541
+ El formato para esta referencia es un signo `+` opcional, seguido de una sentencia `<orig>:<dest>`; donde `<orig>` es la plantilla para referencias en el lado remoto y `<dest>` el lugar donde esas referencias se escribirán en el lado local. El `+`, si está presente, indica a Git que debe actualizar la referencia incluso en los casos en que no se dé un avance rápido (fast-forward).
542
+
543
+ En el caso por defecto en que es escrito por un comando `git remote add`, Git recupera del servidor todas las referencias bajo `refs/heads/`, y las escribe localmente en `refs/remotes/origin/`. De tal forma que, si existe una rama `master` en el servidor, puedes acceder a ella localmente a través de
544
+
545
+ $ git log origin/master
546
+ $ git log remotes/origin/master
547
+ $ git log refs/remotes/origin/master
548
+
549
+ Todas estas sentencias son equivalentes, ya que Git expande cada una de ellas a `refs/remotes/origin/master`.
550
+
551
+ Si, en cambio, quisieras hacer que Git recupere únicamente la rama `master` y no cualquier otra rama en el servidor remoto. Puedes cambiar la linea de recuperación a
552
+
553
+ fetch = +refs/heads/master:refs/remotes/origin/master
554
+
555
+ Quedando así esta referencia como la referencia por defecto para el comando `git fetch` para ese remoto. Para hacerlo puntualmente en un momento concreto, puedes especificar la referencia directamente en la linea de comando. Para recuperar la rama `master` del servidor remoto a tu rama `origin/mymaster` local, puedes lanzar el comando
556
+
557
+ $ git fetch origin master:refs/remotes/origin/mymaster
558
+
559
+ Puedes incluso indicar multiples referencias en un solo comando. Escribiendo algo asi como:
560
+
561
+ $ git fetch origin master:refs/remotes/origin/mymaster \
562
+ topic:refs/remotes/origin/topic
563
+ From git@github.com:schacon/simplegit
564
+ ! [rejected] master -> origin/mymaster (non fast forward)
565
+ * [new branch] topic -> origin/topic
566
+
567
+ En este ejemplo, se ha rechazado la recuperación de la rama master porque no era una referencia de avance rápido (fast-forward). Puedes forzarlo indicando el signo `+` delante de la referencia.
568
+
569
+ Es posible asimismo indicar referencias multiples en el archivo de configuración. Si, por ejemplo, siempre recuperas las ramas 'master' y 'experiment', puedes poner dos lineas:
570
+
571
+ [remote "origin"]
572
+ url = git@github.com:schacon/simplegit-progit.git
573
+ fetch = +refs/heads/master:refs/remotes/origin/master
574
+ fetch = +refs/heads/experiment:refs/remotes/origin/experiment
575
+
576
+ Pero, en ningún caso puedes poner referencias genéricas parciales; por ejemplo, algo como esto sería erroneo:
577
+
578
+ fetch = +refs/heads/qa*:refs/remotes/origin/qa*
579
+
580
+ Aunque, para conseguir algo similar, puedes utilizar los espacios de nombres . Si tienes un equipo QA que envia al servidor una serie de ramas. Y deseas recuperar la rama master y cualquiera otra de las ramas del equipo; pero no recuperar ninguna rama de otro equipo. Puedes utilizar una sección de configuración como esta:
581
+
582
+ [remote "origin"]
583
+ url = git@github.com:schacon/simplegit-progit.git
584
+ fetch = +refs/heads/master:refs/remotes/origin/master
585
+ fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*
586
+
587
+ De esta forma, puedes asignar facilmente espacios de nombres. Y resolver así complejos flujos de trabajo donde tengas simultáneamente , por ejemplo, un equipo QA enviando ramas, varios desarrolladores enviando ramas también y equipos integradores enviando y colaborando en ramas remotas.
588
+
589
+ ### Enviando (push) referencias ###
590
+
591
+ Es util poder recuperar (fetch) referencias relativas en espacios de nombres, tal y como hemos visto. Pero, ¿cómo pueden enviar (push) sus ramas al espacio de nombres `qa/` los miembros de equipo QA ?. Pues utilizando las referencias (refspecs) para enviar.
592
+
593
+ Si alguien del equipo QA quiere enviar su rama `master` a la ubicación `qa/master` en el servidor remoto, puede lanzar algo asi como:
594
+
595
+ $ git push origin master:refs/heads/qa/master
596
+
597
+ Y, para que se haga de forma automática cada vez que ejecute `git push origin`, puede añadir una entrada `push` a su archivo de configuración:
598
+
599
+ [remote "origin"]
600
+ url = git@github.com:schacon/simplegit-progit.git
601
+ fetch = +refs/heads/*:refs/remotes/origin/*
602
+ push = refs/heads/master:refs/heads/qa/master
603
+
604
+ Esto hará que un simple comando `git push origin` envie por defecto la rama local `master` a la rama remota `qa/master`,
605
+
606
+ ### Borrando referencias ###
607
+
608
+ Se pueden utilizar las referencias (refspec) para borrar en el servidor remoto. Por ejemplo, lanzando algo como:
609
+
610
+ $ git push origin :topic
611
+
612
+ Se elimina la rama 'topic' del servidor remoto, ya que la sustituimos or nada. (Al ser la referencia `<origen>:<destino>`, si no indicamos la parte `<origen>`, realmente estamos diciendo que enviamos 'nada' a `<destino>`.)
613
+
614
+ ## Protocolos de transferencia ##
615
+
616
+ Git puede transferir datos entre dos repositorios utilizando uno de sus dos principales mecanismos de transporte: sobre HTTP (protocolo tonto), o sobre los denominados protocolos inteligentes (utilizados en `file://`, `ssh://` o `git://`). En esta parte, se verán sucintamente cómo trabajan esos dos tipos de protocolo.
617
+
618
+ ### El protocolo tonto (dumb) ###
619
+
620
+ El transporte de Git sobre protocolo HTTP es conocido también como protocolo tonto. Porque no requiere ningún tipo de codigo Git en la parte servidor. El proceso de recuperación (fetch) de datos se limita a una serie de peticiones GET, siendo el cliente quien ha de conocer la estructura del repositorio Git en el servidor. Vamos a revisar el proceso `http-fetch` para una libreria simple de Git:
621
+
622
+ $ git clone http://github.com/schacon/simplegit-progit.git
623
+
624
+ Lo primero que hace este comando es recuperar el archivo `info/refs`. Este es un archivo escrito por el comando `update-server-info`, el que has de habilitar como enganche (hook) `post-receive` para permitir funcionar correctamente al transporte HTTP:
625
+
626
+ => GET info/refs
627
+ ca82a6dff817ec66f44342007202690a93763949 refs/heads/master
628
+
629
+ A partir de ahi, ya tienes una lista de las referencias remotas y sus SHAs. Lo siguiente es mirar cual es la referencia a HEAD, de tal forma que puedas saber el punto a activar (checkout) cuando termines:
630
+
631
+ => GET HEAD
632
+ ref: refs/heads/master
633
+
634
+ Ves que es la rama`master` la que has de activar cuando el proceso esté completado.
635
+ sus ramas al espacio de nombres `qa/`En este punto, ya estás preparado para seguir procesando el resto de los objetos. En el archivo `info/refs` se ve que el punto de partida es la confirmación de cambios (commit) `ca82a6`, y, por tanto, comenzaremos recuperandola:
636
+
637
+ => GET objects/ca/82a6dff817ec66f44342007202690a93763949
638
+ (179 bytes of binary data)
639
+
640
+ Cuando recuperas un objeto, dicho objeto se encuentra suelto (loose) en el servidor y lo traes mediante una petición estática HTTP GET. Puedes descomprimirlo, quitarle la cabecera y mirar el contenido:
641
+
642
+ $ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
643
+ tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
644
+ parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
645
+ author Scott Chacon <schacon@gmail.com> 1205815931 -0700
646
+ committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
647
+
648
+ changed the version number
649
+
650
+ Tras esto, ya tienes más objetos a recuperar --el árbol de contenido `cfda3b` al que apunta la confirmación de cambios; y la confirmación de cambios padre `085bb3`--.
651
+
652
+ => GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
653
+ (179 bytes of data)
654
+
655
+ El siguiente objeto confirmación de cambio (commit). Y el árbol de contenido:
656
+
657
+ => GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
658
+ (404 - Not Found)
659
+
660
+ Pero... ¡Ay!... parece que el objeto árbol no está suelto en el servidor. Por lo que obtienes una respuesta 404 (objeto no encontrado). Puede haber un par de razones para que suceda esto: el objeto está en otro repositorio alternativo; o el objeto está en este repositorio, pero dentro de un objeto empaquetador (packfile). Git comprueba primero a ver si en el listado hay alguna alternativa:
661
+
662
+ => GET objects/info/http-alternates
663
+ (empty file)
664
+
665
+ En el caso de que esto devolviera una lista de ubicaciones (URL) alternativas, Git busca en ellas. (Es un mecanismo muy adecuado en aquellos proyectos donde hay segmentos derivados uno de otro compartiendo objetos en disco.) Pero, en este caso, no hay altenativas. Por lo que el objeto debe encontrarse dentro de un empaquetado. Para ver que empaquetados hay disponibles en el servidor, has de recuperar el archivo `objects/info/packs`. Este contiene una lista de todos ellos: (que ha sido generada por `update-server-info`)
666
+
667
+ => GET objects/info/packs
668
+ P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
669
+
670
+ Vemos que hay un archivo empaquetado, y el objeto buscado ha de encontrarse dentro de él; pero merece comprobarlo revisando el archivo de índice, para asegurarse. Hacer la comprobacion es sobre todo util en aquellos casos donde existan multiples archivos empaquetados en el servidor, para determinar así en cual de ellos se encuentra el objeto que necesitas:
671
+
672
+ => GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
673
+ (4k of binary data)
674
+
675
+ Una vez tengas el índice del empaquetado, puedes mirar si el objeto buscado está en él, (Dicho índice contiene la lista de SHAs de los objetos dentro del empaquetado y las ubicaciones -offsets- de cada uno de llos dentro de él.) Una vez comprobada la presencia del objeto, adelante con la recuperación de todo el archivo empaquetado:
676
+
677
+ => GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
678
+ (13k of binary data)
679
+
680
+ Cuando tengas el objeto árbol, puedes continuar avanzando por las confirmaciones de cambio. Y, como estás también están dentro del archivo empaquetado que acabas de descargar, ya no necesitas hacer mas peticiones al servidor. Git activa una copia de trabajo de la rama `master` señalada por la referencia HEAD que has descargado al principio.
681
+
682
+ La salida completa de todo el proceso es algo como esto:
683
+
684
+ $ git clone http://github.com/schacon/simplegit-progit.git
685
+ Initialized empty Git repository in /private/tmp/simplegit-progit/.git/
686
+ got ca82a6dff817ec66f44342007202690a93763949
687
+ walk ca82a6dff817ec66f44342007202690a93763949
688
+ got 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
689
+ Getting alternates list for http://github.com/schacon/simplegit-progit.git
690
+ Getting pack list for http://github.com/schacon/simplegit-progit.git
691
+ Getting index for pack 816a9b2334da9953e530f27bcac22082a9f5b835
692
+ Getting pack 816a9b2334da9953e530f27bcac22082a9f5b835
693
+ which contains cfda3bf379e4f8dba8717dee55aab78aef7f4daf
694
+ walk 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
695
+ walk a11bef06a3f659402fe7563abf99ad00de2209e6
696
+
697
+ ### El protocolo inteligente (smart) ###
698
+
699
+ HTTP es un protocolo simple, pero ineficiente. Es mucho más común utilizar protocolos inteligentes para transferir datos. Estos protocolos suelen tener procesos en el lado remoto y conocen acerca de la estructura de datos Git en ese lado, --pueden leer datos localmente y determinar lo que el cliente tiene ya o necesita a continuación, para generar automáticamente datos expresamente preparados para él--. Existen dos conjuntos de procesos para transferir datos: uno para para enviar y otro par para recibir.
700
+
701
+ #### Enviando datos, (Uploading) ####
702
+
703
+ Para enviar datos a un proceso remoto, Git utliza `send-pack` (enviar paquete) y `receive-pack` (recibir paquete). El proceso `send-pack` corre en el cliente y conecta con el proceso `receive-pack` corriendo en el lado remoto.
704
+
705
+ Por ejemplo, si lanzas el comando `git push origin master` en tu proyecto y `origin` está definida como una ubicación que utiliza el protocolo SSH. Git lanzará el proceso `send-pack` , con el que establece conexión SSH con tu servidor. En el servidor remoto, a través de una llamada SSH, intentará lanzar un comando tal como:
706
+
707
+ $ ssh -x git@github.com "git-receive-pack 'schacon/simplegit-progit.git'"
708
+ 005bca82a6dff817ec66f4437202690a93763949 refs/heads/master report-status delete-refs
709
+ 003e085bb3bcb608e1e84b2432f8ecbe6306e7e7 refs/heads/topic
710
+ 0000
711
+
712
+ El comando `git-receive-pack` responde con una linea por cada una de las referencias que tenga, --en este caso, la rama `master` y su SHA--. La primera linea suele indicar también una lista con las capacidades del servidor, (en este caso `report-status` --dar situación-- y `delete-refs` --borrar referencias--).
713
+
714
+ Cada linea comienza con un valor de 4 bytes, en hexadecimal, indicando la longitud del resto de la linea. La primera de las lineas comienza con 005b, 91 en decimal, indicandonos que hay 91 bytes más en esa línea. La siguiente línea comienza con 003e, 62 en decimal, por lo que has de leer otros 62 bytes hasta el final de la linea. Y la última linea comienza con 0000, indicando así que la lista de referencias ha terminado.
715
+
716
+ Con esta información, el proceso `send-pack` ya puede determnar las confirmaciones de cambios (commits) presentes en el servidor. Para cada una de las referencias que se van a actualizar, el proceso `send-pack` llama al proceso `receive-pack` con la información pertinente. Por ejemplo, si estás actualizando la rama `master` y añadiendo otra rama `experiment`, la respuesta del proceso `send-pack` será algo así como:
717
+
718
+ 0085ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 refs/heads/master report-status
719
+ 00670000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d refs/heads/experiment
720
+ 0000
721
+
722
+ Una clave SHA-1 con todo '0's, nos indica que no habia nada anteriormente, y que, por tanto, estamos añadiendo una nueva referencia. Si estuvieras borrando una referencia existente, verias lo contrario: una clave todo '0's en el lado derecho.
723
+
724
+ Git envia una linea por cada referencia a actualizar, indicando el viejo SHA, el nuevo SHA y la referencia a actualizar. La primera linea indica también las capacidades disponibles en el cliente. A continuación, el cliente envia un archivo empaquetado con todos los objetos que faltan en el servidor. Y, por ultimo, el servidor responde con un indicador de éxito (o fracaso) de la operación:
725
+
726
+ 000Aunpack ok
727
+
728
+ #### Descargando datos, (Downloading) ####
729
+
730
+ Cuando descargas datos, los procesos que se ven envueltos son `fetch-pack` (recuperar paquete) y `upload-pack` (enviar paquete). El cliente arranca un proceso `fetch-pack`, para conectar con un proceso `upload-pack` en el lado servidor y negociar con él los datos a transferir.
731
+
732
+ Hay varias maneras de iniciar un proceso `upload-pack` en el repositorio remoto. Se puede lanzar a través de SSH, de la misma forma que se arrancaba el proceso `receive-pack`. O se puede arrancar a traves del demonio Git, que suele estar escuchando por el puerto 9418. Tras la conexión, el proceso `fetch-pack` envia datos de una forma parecida a esta:
733
+
734
+ 003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0
735
+
736
+ Como siempre, comienza con 4 bytes indicadores de cuantos datos siguen a continuación, siguiendo con el comando a lanzar, y terminando con un byte nulo, el nombre del servidor y otro byte nulo más. El demonio Git realizará las comprobaciones de si el comando se puede lanzar, si el repositorio existe y si tenemos permisos. Siendo todo correcto, el demonio lanzará el proceso `upload-pack` y procesara nuestra petición.
737
+
738
+ Si en lugar de utilizar el demonio Git, estás utilizando el protocolo SSH. `fetch-pack` lanzará algo como esto:
739
+
740
+ $ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"
741
+
742
+ En cualquier caso, después de establecer conexión, `upload-pack` responderá:
743
+
744
+ 0088ca82a6dff817ec66f44342007202690a93763949 HEAD\0multi_ack thin-pack \
745
+ side-band side-band-64k ofs-delta shallow no-progress include-tag
746
+ 003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
747
+ 003e085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 refs/heads/topic
748
+ 0000
749
+
750
+ La respuesta es muy similar a la dada por `receive-pack`, pero las capacidades que se indican son diferentes. Además, nos indica la referencia HEAD, para que el cliente pueda saber qué ha de activar (check out) en el caso de estar requiriendo un clon.
751
+
752
+ En este punto, el proceso `fetch-pack` revisa los objetos que tiene y responde indicando los objetos que necesita. Enviando "want" (quiero) y la clave SHA que necesita. Los objetos que ya tiene, los envia con "have" (tengo) y la correspondiente clave SHA. Llegando al final de la lista, escribe "done" (hecho). Para indicar al proceso `upload-pack` que ya puede comenzar a enviar el archivo empaquetado con los datos requeridos:
753
+
754
+ 0054want ca82a6dff817ec66f44342007202690a93763949 ofs-delta
755
+ 0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
756
+ 0000
757
+ 0009done
758
+
759
+ Este es un caso muy sencillo para ilustrar los protocolos de trasferencia. En casos más complejos, el cliente explota las capacidades de `multi_ack` (multiples confirmaciones) o `side-band` (banda lateral). Pero este ejemplo muestra los intercambios básicos empleados en los protocolos inteligentes.
760
+
761
+ ## Mantenimiento y recuperación de datos ##
762
+
763
+ De vez en cuando, es posible que necesites hacer algo de limpieza, (compactar un repositorio, adecuar un repositorio importado, recuperar trabajo perdido,...). En ese apartado vamos a ver algunos de esos escenarios.
764
+
765
+ ### Mantenimiento ###
766
+
767
+ De cuando en cuando, Git lanza automáticamente un comando llamado "auto gc". La mayor parte de las veces, este comando no hace nada. Pero, cuando hay demasiados objetos sueltos, (objetos fuera de un archivo empaquetador), o demasiados archivos empaquetadores, Git lanza un comando `git gc` completo. `gc` corresponde a "recogida de basura" (garbage collect), y este comando realiza toda una serie de acciones: recoge los objetos sueltos y los agrupa en archivos empaquetadores; consolida los archivos empaquetadores pequeños en un solo gran archivo empaquetador; retira los objetos antiguos no incorporados a ninguna confirmación de cambios.
768
+
769
+ También puedes lanzar "auto gc" manualmente:
770
+
771
+ $ git gc --auto
772
+
773
+ Y, habitualmente, no hará nada. Ya que es necesaria la presencia de unos 7.000 objetos sueltos o más de 50 archivos empaquetadores para que Git termine lanzando realmente un comando "gc". Estos límites pueden configurarse con las opciones de configuración `gc.auto` y `gc.autopacklimit`, respectivamente.
774
+
775
+ Otra tarea realizada por `gc` es el empaquetar referencias en un solo archivo. Por ejemplo, suponiendo que tienes las siguientes ramas y etiquetas en tu repositorio:
776
+
777
+ $ find .git/refs -type f
778
+ .git/refs/heads/experiment
779
+ .git/refs/heads/master
780
+ .git/refs/tags/v1.0
781
+ .git/refs/tags/v1.1
782
+
783
+ Lanzando el comando `git gc`, dejarás de tener esos archivos en la carpeta `refs`. En aras de la eficiencia, Git los moverá a un archivo denominado `.git/packed-refs`:
784
+
785
+ $ cat .git/packed-refs
786
+ # pack-refs with: peeled
787
+ cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
788
+ ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
789
+ cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
790
+ 9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
791
+ ^1a410efbd13591db07496601ebc7a059dd55cfe9
792
+
793
+ Si actualizas alguna de las referencias, Git no modificará este archivo. Sino que, en cambio, escribirá uno nuevo en `refs/heads`. Para obtener la clave SHA correspondiente a una determinada referencia, Git comprobará primero en la carpeta `refs` y luego en el archivo `packed-refs`. Cualquier referencia que no puedas encontrar en la carpeta `refs`, es muy posible que la encuentres en el archivo `packed-refs`.
794
+
795
+ Merece destacar que la última línea de este archivo comenzaba con `^`- Esto nos indica que la etiqueta inmediatamente anterior es una etiqueta anotada y que esa línea es la confirmación de cambios a la que apunta dicha etiqueta anotada.
796
+
797
+ ### Recuperación de datos ###
798
+
799
+ En algún momento de tu trabajo con Git, perderás por error una confirmación de cambios. Normalmente, esto suele suceder porque has forzado el borrado de una rama con trabajos no confirmados en ella, y luego te has dado cuenta de que realmente necesitabas dicha rama; o porque has reculado (hard-reset) una rama, abandonando todas sus confirmaciones de cambio, y luego te has dado cuenta que necesitabas alguna de ellas. Asumiendo que estas cosas pasan, ¿cómo podrías recuperar tus confirmaciones de cambio perdidas?
800
+
801
+ Vamos a ver un ejemplo de un retroceso a una confirmación (commit) antigua en la rama principal de tu repositorio de pruebas, y cómo podriamos recuperar las confirmaciones perdidas en este caso. Lo primero es revisar el estado de tu repositorio en ese momento:
802
+
803
+ $ git log --pretty=oneline
804
+ ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
805
+ 484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
806
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
807
+ cac0cab538b970a37ea1e769cbbde608743bc96d second commit
808
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
809
+
810
+ Después, al mover la rama `master` de vuelta a la confirmación de cambios intermedia:
811
+
812
+ $ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
813
+ HEAD is now at 1a410ef third commit
814
+ $ git log --pretty=oneline
815
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
816
+ cac0cab538b970a37ea1e769cbbde608743bc96d second commit
817
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
818
+
819
+ Vemos que se han perdido las dos últimas confirmaciones de cambios, --no tienes ninguna rama que te permita acceder a ellas--. Necesitas localizar el SHA de la última confirmación de cambios y luego añadir una rama que apunte hacia ella. El problema es cómo localizarla, --porque, ¿no te la sabrás de memoria, no?--.
820
+
821
+ El método más rápido para conseguirlo suele ser utilizar una herramienta denominada `git reflog`. Según trabajas, Git suele guardar un silencioso registro de donde está HEAD en cada momento. Cada vez que confirmas cambios o cambias de rama, el registro (reflog) es actualizado. El registro reflog se actualiza incluso cuando utilizas el comando `git update-ref`. Siendo esta otra de las razones por las que es recomendable utilizar ese comando en lugar de escribir manualmente los valores SHA en los archivos de referencia, tal y como hemos visto anteriormente en la sección "Referencias Git". Con el comando `git reflog` puedes revisar donde has estado en cualquier momento pasado:
822
+
823
+ $ git reflog
824
+ 1a410ef HEAD@{0}: 1a410efbd13591db07496601ebc7a059dd55cfe9: updating HEAD
825
+ ab1afef HEAD@{1}: ab1afef80fac8e34258ff41fc1b867c702daa24b: updating HEAD
826
+
827
+ Se pueden ver las dos confirmaciones de cambios que hemos activado, pero no hay mucha más información al respecto. Para ver la misma información de manera mucho más amigable, podemos utilizar el comando `git log -g`. Este nos muestra una salida normal de registro:
828
+
829
+ $ git log -g
830
+ commit 1a410efbd13591db07496601ebc7a059dd55cfe9
831
+ Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
832
+ Reflog message: updating HEAD
833
+ Author: Scott Chacon <schacon@gmail.com>
834
+ Date: Fri May 22 18:22:37 2009 -0700
835
+
836
+ third commit
837
+
838
+ commit ab1afef80fac8e34258ff41fc1b867c702daa24b
839
+ Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
840
+ Reflog message: updating HEAD
841
+ Author: Scott Chacon <schacon@gmail.com>
842
+ Date: Fri May 22 18:15:24 2009 -0700
843
+
844
+ modified repo a bit
845
+
846
+ Parece que la confirmación de cambios perdida es esta última. Puedes recuperarla creando una nueva rama apuntando a ella. Por ejemplo, puedes iniciar una rama llamada `recover-branch` con dicha confirmación de cambios (ab1afef):
847
+
848
+ $ git branch recover-branch ab1afef
849
+ $ git log --pretty=oneline recover-branch
850
+ ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
851
+ 484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
852
+ 1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
853
+ cac0cab538b970a37ea1e769cbbde608743bc96d second commit
854
+ fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
855
+
856
+ ¡Bravo!, acabas de añadir una rama denominada `recover-branch` al punto donde estaba originalmente tu rama `master`; permitiendo así recuperar el acceso a las dos primeras confirmaciones de cambios.
857
+ A continuación, supongamos que la pérdida se ha producido por alguna razón que no se refleja en el registro (reflog). Puedes simularlo borrando la rama `recover-branch` y borrando asimismo el registro. Con eso, perdemos completamente el acceso a las dos primeras confirmaciones de cambio:
858
+
859
+ $ git branch –D recover-branch
860
+ $ rm -Rf .git/logs/
861
+
862
+ La información de registro (reflog) se guarda en la carpeta `.git/logs/`; por lo que, borrandola, nos quedamos efectivamente sin registro. ¿Cómo podriamos ahora recuperar esas confirmaciones de cambio? Un camino es utilizando el comando de chequeo de integridad de la base de datos: `git fsck`. Si lo lanzas con la opción `--full`, te mostrará todos los objetos sin referencias a ningún otro objeto:
863
+
864
+ $ git fsck --full
865
+ dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
866
+ dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
867
+ dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
868
+ dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
869
+
870
+ En este caso, puedes ver la confirmación de cambios perdida en la línea 'dangling commit.....'. Y la puedes recuperar del mismo modo, añadiendo una rama que apunte a esa clave SHA.
871
+
872
+ ### Borrando objetos ###
873
+
874
+ Git tiene grandes cosas. Pero el hecho de que un `git clone` siempre descarge la historia completa del proyecto (incluyendo todas y cada una de las versiones de todos y cada uno de los archivos). Puede casusar problemas. Todo suele ir bien si el contenido es únicamente código fuente. Ya que Git está tremendamente optimizado para comprimir eficientemente ese tipo de datos. Pero, si alguien, en cualquier momento de tu proyecto, ha añadido un solo archivo enorme. A partir de ese momento, todos los clones, siempre, se verán obligados a copiar ese enorme archivo. Incluso si ya ha sido borrado del proyecto en la siguiente confirmación de cambios realizada inmediatamente tras la que lo añadió. Porque en algún momento formó parte del proyecto, siempre permanecerá ahí.
875
+
876
+ Esto suele dar bastantes problemas cuando estás convirtiendo repositorios de Subversion o de Perforce a Git. En esos sistemas, uno no se suele descargar la historia completa. Y, por tanto, los archivos enormes no tienen mayores consecuencias. Si, tras una importación de otro sistema, o por otras razones, descubres que tu repositorio es mucho mayor de lo que deberia ser. Es momento de buscar y borrar objetos enormes en él.
877
+
878
+ Una advertencia importante: estas técnicas son destructivas y alteran el historia de confirmaciones de cambio. Se basan en reescribir todos los objetos confirmados aguas abajo desde el árbol más reciente modificado para borrar la referencia a un archivo enorme. No tendrás problemas si lo haces inmediatamente despues de una importación; o justo antes de que alguien haya comenzado a trabajar con la confirmación de cambios modificada. Pero si no es el caso, tendrás que avisar a todas las personas que hayan contribuido. Porque se verán obligadas a reorganizar su trabajo en base a tus nuevas confirmaciones de cambio.
879
+
880
+ Para probarlo por tí mismo, puedes añadir un archivo enorme a tu repositorio de pruebas y retirarlo en la siguiente confirmación de cambios. Así podrás practicar la busqueda y borrado permanente del repositorio. Para emprezar, añade un objeto enorme a tu historial:
881
+
882
+ $ curl http://kernel.org/pub/software/scm/git/git-1.6.3.1.tar.bz2 > git.tbz2
883
+ $ git add git.tbz2
884
+ $ git commit -am 'added git tarball'
885
+ [master 6df7640] added git tarball
886
+ 1 files changed, 0 insertions(+), 0 deletions(-)
887
+ create mode 100644 git.tbz2
888
+
889
+ !Ouch!, --no querias añadir un archivo tan grande a tu proyecto--. Mejor si lo quitas:
890
+
891
+ $ git rm git.tbz2
892
+ rm 'git.tbz2'
893
+ $ git commit -m 'oops - removed large tarball'
894
+ [master da3f30d] oops - removed large tarball
895
+ 1 files changed, 0 insertions(+), 0 deletions(-)
896
+ delete mode 100644 git.tbz2
897
+
898
+ Ahora, puedes limpiar `gc` tu base de datos y comprobar cuánto espacio estás ocupando:
899
+
900
+ $ git gc
901
+ Counting objects: 21, done.
902
+ Delta compression using 2 threads.
903
+ Compressing objects: 100% (16/16), done.
904
+ Writing objects: 100% (21/21), done.
905
+ Total 21 (delta 3), reused 15 (delta 1)
906
+
907
+ Puedes utilizar el comando `count-objects` para revisar rápidamente el espacio utilizado:
908
+
909
+ $ git count-objects -v
910
+ count: 4
911
+ size: 16
912
+ in-pack: 21
913
+ packs: 1
914
+ size-pack: 2016
915
+ prune-packable: 0
916
+ garbage: 0
917
+
918
+ El valor de `size-pack` nos da el tamaño de tus archivos empaquetadores, en kilobytes, y, por lo que se ve, estás usando 2 MB. Antes de la última confirmación de cambios, estabas usando algo así como 2 KB. Resulta claro que esa última confirmación de cambios no ha borrado el archivo enorme del historial. A partir de este momento, cada vez que alguien haga un clón de este repositorio, se verá obligado a copiar 2 MB para un proyecto tan simple. Y todo porque tu añadiste accidentalmente un archivo enorme en algún momento. Para arreglar la situación.
919
+
920
+ Lo primero es localizar el archivo enorme. En este caso, ya sabes de antemano cual es. Pero suponiendo que no lo supieras, ¿cómo podrías identificar el archivo o archivos que están ocupando tanto espacio?. Tras lanzar el comando `git gc`, todos los objetos estarán guardados en un archivo empaquetador. Puedes identifcar los objetos enormes en su interior, utilizando otro comando de fontanería denominado `git verify-pack` y ordenando su salida por su tercera columna, la que nos informa de los tamaños de cada objeto. Puedes también redirigir su salida a través del comando `tail`. Porque realmente solo nos interesan las últimas líneas, las correspondientes a los archivos más grandes.
921
+
922
+ $ git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3
923
+ e3f094f522629ae358806b17daf78246c27c007b blob 1486 734 4667
924
+ 05408d195263d853f09dca71d55116663690c27c blob 12908 3478 1189
925
+ 7a9eb2fba2b1811321254ac360970fc169ba2330 blob 2056716 2056872 5401
926
+
927
+ El archivo enorme es el último: 2 MB (2056716 Bytes para ser exactos). Para concretar cual es el archivo, puedes utilizar el comando `rev-list` que ya vimos brevemente en el capítulo 7. Con la opción `--objects`, obtendrás la lista de todas las SHA de todas las confirmaciones de cambio, junto a las SHA de los objetos binarios y las ubicaciones (paths) de cada uno de ellos. Puedes usar esta información para localizar el nombre del objeto binario:
928
+
929
+ $ git rev-list --objects --all | grep 7a9eb2fb
930
+ 7a9eb2fba2b1811321254ac360970fc169ba2330 git.tbz2
931
+
932
+ Una vez tengas ese dato, lo puedes utilizar para borrar ese archivo en todos los árboles pasados. Es sencillo revisar cuales son las confirmaciones de cambios donde interviene ese archivo:
933
+
934
+ $ git log --pretty=oneline --branches -- git.tbz2
935
+ da3f30d019005479c99eb4c3406225613985a1db oops - removed large tarball
936
+ 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 added git tarball
937
+
938
+ Para borrar realmente ese archivo de tu historial Git, has de reescribir todas las confirmaciones de cambio aguas abajo de `6df76`. Y, para ello, puedes emplear el comando `filter-branch` que se vió en el capítulo 6.
939
+
940
+ $ git filter-branch --index-filter \
941
+ 'git rm --cached --ignore-unmatch git.tbz2' -- 6df7640^..
942
+ Rewrite 6df764092f3e7c8f5f94cbe08ee5cf42e92a0289 (1/2)rm 'git.tbz2'
943
+ Rewrite da3f30d019005479c99eb4c3406225613985a1db (2/2)
944
+ Ref 'refs/heads/master' was rewritten
945
+
946
+ La opción `--index-filter` es similar a la `--tree-filter` vista en el capítulo 6. Se diferencia porque, en lugar de modificar archivos activados (checked out) en el disco, se modifica el área de preparación (staging area) o índice. En lugar de borrar un archivo concreto con una orden tal como `rm archivo`, has de borrarlo con `git rm --cached` (es decir, tienes que borrarlo del índice, en lugar de del disco). Con eso conseguimos aumentar la velocidad. El proceso es mucho más rápido, porque Git no ha de activar cada revisión a disco antes de procesar tu filtro. Aunque también puedes hacer lo mismo con la opción`--tree-filter`, si así lo prefieres. La opción `--ignore-unmatch` indica a `git rm` que evite lanzar errores en caso de no encontrar el patrón que le has ordenado buscar. Y por último, se indica a `filter-branch` que reescriba la historia a partir de la confirmación de cambios `6df7640`, porque ya conocemos que es a partir de ahí donde comenzaba el problema. De otro modo, el comando comenzaria desde el principio, asumiendo un proceso inecesariamente más largo.
947
+
948
+ Tras esto, el historial ya no contiene ninguna referencia a ese archivo. Pero, sin embargo, quedan referencias en el registro (reflog) y en el nuevo conjunto de referencias en `.git/refs/original` que Git ha añadido al procesar `filter-branch`. Por lo que has de borrar también estás y reempaquetar la base de datos. Antes de reempaquetar, asegurate de acabar completamente con cualquier elemento que apunte a las viejas confirmaciones de cambios:
949
+
950
+ $ rm -Rf .git/refs/original
951
+ $ rm -Rf .git/logs/
952
+ $ git gc
953
+ Counting objects: 19, done.
954
+ Delta compression using 2 threads.
955
+ Compressing objects: 100% (14/14), done.
956
+ Writing objects: 100% (19/19), done.
957
+ Total 19 (delta 3), reused 16 (delta 1)
958
+
959
+ Y ahora, vamos a ver cuanto espacio hemos ahorrado.
960
+
961
+ $ git count-objects -v
962
+ count: 8
963
+ size: 2040
964
+ in-pack: 19
965
+ packs: 1
966
+ size-pack: 7
967
+ prune-packable: 0
968
+ garbage: 0
969
+
970
+ El tamaño del repositorio ahora es de 7 KB, mucho mejor que los 2 MB anteriores. Por el valor de "size", puedes ver que el objeto enorme sigue estando entre tus objetos sueltos; es decir, no hemos acabado completamente con él. Pero lo importante es que ya no será considerado al transferir o clonar el proyecto. Si realmente quieres acabar del todo, puedes lanzar la orden `git prune --expire` para retirar incluso ese archivo suelto.
971
+
972
+ ## Recapitulación ##
973
+
974
+ A estas alturas deberias tener una idea bastante clara de como trabaja Git entre bastidores. Y, hasta cierto punto, sobre cómo está implementado. En este capítulo se han visto unos cuantos comandos "de fontanería". Comandos de menor nivel y más simples que los "de porcelana" que hemos estado viendo en el resto del libro. Entendiendo cómo trabaja Git a bajo nivel, es más sencillo comprenderestán por qué hace lo que hace. A la par que facilita la escritura de tus propias herramientas y scripts auxiliares para implementar flujos de trabajo tal y como necesites.
975
+
976
+ Git, en su calidad de sistema de archivos indexador-de-contenidos, es una herramienta muy poderosa que puedes usar facilmente para otras tareas ademas de la de gestión de versiones. Espero que uses este nuevo conocimiento profundo de las entrañas de Git para implementar tus propias aplicaciones y para que te encuentres más confortable trabajando con Git de forma avanzada.