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,1126 @@
1
+ # Git Tools #
2
+
3
+ By now, you’ve learned most of the day-to-day commands and workflows that you need to manage or maintain a Git repository for your source code control. You’ve accomplished the basic tasks of tracking and committing files, and you’ve harnessed the power of the staging area and lightweight topic branching and merging.
4
+
5
+ Now you’ll explore a number of very powerful things that Git can do that you may not necessarily use on a day-to-day basis but that you may need at some point.
6
+
7
+ ## Revision Selection ##
8
+
9
+ Git allows you to specify specific commits or a range of commits in several ways. They aren’t necessarily obvious but are helpful to know.
10
+
11
+ ### Single Revisions ###
12
+
13
+ You can obviously refer to a commit by the SHA-1 hash that it’s given, but there are more human-friendly ways to refer to commits as well. This section outlines the various ways you can refer to a single commit.
14
+
15
+ ### Short SHA ###
16
+
17
+ Git is smart enough to figure out what commit you meant to type if you provide the first few characters, as long as your partial SHA-1 is at least four characters long and unambiguous — that is, only one object in the current repository begins with that partial SHA-1.
18
+
19
+ For example, to see a specific commit, suppose you run a `git log` command and identify the commit where you added certain functionality:
20
+
21
+ $ git log
22
+ commit 734713bc047d87bf7eac9674765ae793478c50d3
23
+ Author: Scott Chacon <schacon@gmail.com>
24
+ Date: Fri Jan 2 18:32:33 2009 -0800
25
+
26
+ fixed refs handling, added gc auto, updated tests
27
+
28
+ commit d921970aadf03b3cf0e71becdaab3147ba71cdef
29
+ Merge: 1c002dd... 35cfb2b...
30
+ Author: Scott Chacon <schacon@gmail.com>
31
+ Date: Thu Dec 11 15:08:43 2008 -0800
32
+
33
+ Merge commit 'phedders/rdocs'
34
+
35
+ commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
36
+ Author: Scott Chacon <schacon@gmail.com>
37
+ Date: Thu Dec 11 14:58:32 2008 -0800
38
+
39
+ added some blame and merge stuff
40
+
41
+ In this case, choose `1c002dd....` If you `git show` that commit, the following commands are equivalent (assuming the shorter versions are unambiguous):
42
+
43
+ $ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
44
+ $ git show 1c002dd4b536e7479f
45
+ $ git show 1c002d
46
+
47
+ Git can figure out a short, unique abbreviation for your SHA-1 values. If you pass `--abbrev-commit` to the `git log` command, the output will use shorter values but keep them unique; it defaults to using seven characters but makes them longer if necessary to keep the SHA-1 unambiguous:
48
+
49
+ $ git log --abbrev-commit --pretty=oneline
50
+ ca82a6d changed the version number
51
+ 085bb3b removed unnecessary test code
52
+ a11bef0 first commit
53
+
54
+ Generally, eight to ten characters are more than enough to be unique within a project. One of the largest Git projects, the Linux kernel, is beginning to need 12 characters out of the possible 40 to stay unique.
55
+
56
+ ### A SHORT NOTE ABOUT SHA-1 ###
57
+
58
+ A lot of people become concerned at some point that they will, by random happenstance, have two objects in their repository that hash to the same SHA-1 value. What then?
59
+
60
+ If you do happen to commit an object that hashes to the same SHA-1 value as a previous object in your repository, Git will see the previous object already in your Git database and assume it was already written. If you try to check out that object again at some point, you’ll always get the data of the first object.
61
+
62
+ However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160)`). 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth.
63
+
64
+ Here’s an example to give you an idea of what it would take to get a SHA-1 collision. If all 6.5 billion humans on Earth were programming, and every second, each one was producing code that was the equivalent of the entire Linux kernel history (1 million Git objects) and pushing it into one enormous Git repository, it would take 5 years until that repository contained enough objects to have a 50% probability of a single SHA-1 object collision. A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night.
65
+
66
+ ### Branch References ###
67
+
68
+ The most straightforward way to specify a commit requires that it have a branch reference pointed at it. Then, you can use a branch name in any Git command that expects a commit object or SHA-1 value. For instance, if you want to show the last commit object on a branch, the following commands are equivalent, assuming that the `topic1` branch points to `ca82a6d`:
69
+
70
+ $ git show ca82a6dff817ec66f44342007202690a93763949
71
+ $ git show topic1
72
+
73
+ If you want to see which specific SHA a branch points to, or if you want to see what any of these examples boils down to in terms of SHAs, you can use a Git plumbing tool called `rev-parse`. You can see Chapter 9 for more information about plumbing tools; basically, `rev-parse` exists for lower-level operations and isn’t designed to be used in day-to-day operations. However, it can be helpful sometimes when you need to see what’s really going on. Here you can run `rev-parse` on your branch.
74
+
75
+ $ git rev-parse topic1
76
+ ca82a6dff817ec66f44342007202690a93763949
77
+
78
+ ### RefLog Shortnames ###
79
+
80
+ One of the things Git does in the background while you’re working away is keep a reflog — a log of where your HEAD and branch references have been for the last few months.
81
+
82
+ You can see your reflog by using `git reflog`:
83
+
84
+ $ git reflog
85
+ 734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated
86
+ d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
87
+ 1c002dd... HEAD@{2}: commit: added some blame and merge stuff
88
+ 1c36188... HEAD@{3}: rebase -i (squash): updating HEAD
89
+ 95df984... HEAD@{4}: commit: # This is a combination of two commits.
90
+ 1c36188... HEAD@{5}: rebase -i (squash): updating HEAD
91
+ 7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD
92
+
93
+ Every time your branch tip is updated for any reason, Git stores that information for you in this temporary history. And you can specify older commits with this data, as well. If you want to see the fifth prior value of the HEAD of your repository, you can use the `@{n}` reference that you see in the reflog output:
94
+
95
+ $ git show HEAD@{5}
96
+
97
+ You can also use this syntax to see where a branch was some specific amount of time ago. For instance, to see where your `master` branch was yesterday, you can type
98
+
99
+ $ git show master@{yesterday}
100
+
101
+ That shows you where the branch tip was yesterday. This technique only works for data that’s still in your reflog, so you can’t use it to look for commits older than a few months.
102
+
103
+ To see reflog information formatted like the `git log` output, you can run `git log -g`:
104
+
105
+ $ git log -g master
106
+ commit 734713bc047d87bf7eac9674765ae793478c50d3
107
+ Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
108
+ Reflog message: commit: fixed refs handling, added gc auto, updated
109
+ Author: Scott Chacon <schacon@gmail.com>
110
+ Date: Fri Jan 2 18:32:33 2009 -0800
111
+
112
+ fixed refs handling, added gc auto, updated tests
113
+
114
+ commit d921970aadf03b3cf0e71becdaab3147ba71cdef
115
+ Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
116
+ Reflog message: merge phedders/rdocs: Merge made by recursive.
117
+ Author: Scott Chacon <schacon@gmail.com>
118
+ Date: Thu Dec 11 15:08:43 2008 -0800
119
+
120
+ Merge commit 'phedders/rdocs'
121
+
122
+ It’s important to note that the reflog information is strictly local — it’s a log of what you’ve done in your repository. The references won’t be the same on someone else’s copy of the repository; and right after you initially clone a repository, you'll have an empty reflog, as no activity has occurred yet in your repository. Running `git show HEAD@{2.months.ago}` will work only if you cloned the project at least two months ago — if you cloned it five minutes ago, you’ll get no results.
123
+
124
+ ### Ancestry References ###
125
+
126
+ The other main way to specify a commit is via its ancestry. If you place a `^` at the end of a reference, Git resolves it to mean the parent of that commit.
127
+ Suppose you look at the history of your project:
128
+
129
+ $ git log --pretty=format:'%h %s' --graph
130
+ * 734713b fixed refs handling, added gc auto, updated tests
131
+ * d921970 Merge commit 'phedders/rdocs'
132
+ |\
133
+ | * 35cfb2b Some rdoc changes
134
+ * | 1c002dd added some blame and merge stuff
135
+ |/
136
+ * 1c36188 ignore *.gem
137
+ * 9b29157 add open3_detach to gemspec file list
138
+
139
+ Then, you can see the previous commit by specifying `HEAD^`, which means "the parent of HEAD":
140
+
141
+ $ git show HEAD^
142
+ commit d921970aadf03b3cf0e71becdaab3147ba71cdef
143
+ Merge: 1c002dd... 35cfb2b...
144
+ Author: Scott Chacon <schacon@gmail.com>
145
+ Date: Thu Dec 11 15:08:43 2008 -0800
146
+
147
+ Merge commit 'phedders/rdocs'
148
+
149
+ You can also specify a number after the `^` — for example, `d921970^2` means "the second parent of d921970." This syntax is only useful for merge commits, which have more than one parent. The first parent is the branch you were on when you merged, and the second is the commit on the branch that you merged in:
150
+
151
+ $ git show d921970^
152
+ commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
153
+ Author: Scott Chacon <schacon@gmail.com>
154
+ Date: Thu Dec 11 14:58:32 2008 -0800
155
+
156
+ added some blame and merge stuff
157
+
158
+ $ git show d921970^2
159
+ commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
160
+ Author: Paul Hedderly <paul+git@mjr.org>
161
+ Date: Wed Dec 10 22:22:03 2008 +0000
162
+
163
+ Some rdoc changes
164
+
165
+ The other main ancestry specification is the `~`. This also refers to the first parent, so `HEAD~` and `HEAD^` are equivalent. The difference becomes apparent when you specify a number. `HEAD~2` means "the first parent of the first parent," or "the grandparent" — it traverses the first parents the number of times you specify. For example, in the history listed earlier, `HEAD~3` would be
166
+
167
+ $ git show HEAD~3
168
+ commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
169
+ Author: Tom Preston-Werner <tom@mojombo.com>
170
+ Date: Fri Nov 7 13:47:59 2008 -0500
171
+
172
+ ignore *.gem
173
+
174
+ This can also be written `HEAD^^^`, which again is the first parent of the first parent of the first parent:
175
+
176
+ $ git show HEAD^^^
177
+ commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
178
+ Author: Tom Preston-Werner <tom@mojombo.com>
179
+ Date: Fri Nov 7 13:47:59 2008 -0500
180
+
181
+ ignore *.gem
182
+
183
+ You can also combine these syntaxes — you can get the second parent of the previous reference (assuming it was a merge commit) by using `HEAD~3^2`, and so on.
184
+
185
+ ### Commit Ranges ###
186
+
187
+ Now that you can specify individual commits, let’s see how to specify ranges of commits. This is particularly useful for managing your branches — if you have a lot of branches, you can use range specifications to answer questions such as, "What work is on this branch that I haven’t yet merged into my main branch?"
188
+
189
+ #### Double Dot ####
190
+
191
+ The most common range specification is the double-dot syntax. This basically asks Git to resolve a range of commits that are reachable from one commit but aren’t reachable from another. For example, say you have a commit history that looks like Figure 6-1.
192
+
193
+ Insert 18333fig0601.png
194
+ Figure 6-1. Example history for range selection.
195
+
196
+ You want to see what is in your experiment branch that hasn’t yet been merged into your master branch. You can ask Git to show you a log of just those commits with `master..experiment` — that means "all commits reachable by experiment that aren’t reachable by master." For the sake of brevity and clarity in these examples, I’ll use the letters of the commit objects from the diagram in place of the actual log output in the order that they would display:
197
+
198
+ $ git log master..experiment
199
+ D
200
+ C
201
+
202
+ If, on the other hand, you want to see the opposite — all commits in `master` that aren’t in `experiment` — you can reverse the branch names. `experiment..master` shows you everything in `master` not reachable from `experiment`:
203
+
204
+ $ git log experiment..master
205
+ F
206
+ E
207
+
208
+ This is useful if you want to keep the `experiment` branch up to date and preview what you’re about to merge in. Another very frequent use of this syntax is to see what you’re about to push to a remote:
209
+
210
+ $ git log origin/master..HEAD
211
+
212
+ This command shows you any commits in your current branch that aren’t in the `master` branch on your `origin` remote. If you run a `git push` and your current branch is tracking `origin/master`, the commits listed by `git log origin/master..HEAD` are the commits that will be transferred to the server.
213
+ You can also leave off one side of the syntax to have Git assume HEAD. For example, you can get the same results as in the previous example by typing `git log origin/master..` — Git substitutes HEAD if one side is missing.
214
+
215
+ #### Multiple Points ####
216
+
217
+ The double-dot syntax is useful as a shorthand; but perhaps you want to specify more than two branches to indicate your revision, such as seeing what commits are in any of several branches that aren’t in the branch you’re currently on. Git allows you to do this by using either the `^` character or `--not` before any reference from which you don’t want to see reachable commits. Thus these three commands are equivalent:
218
+
219
+ $ git log refA..refB
220
+ $ git log ^refA refB
221
+ $ git log refB --not refA
222
+
223
+ This is nice because with this syntax you can specify more than two references in your query, which you cannot do with the double-dot syntax. For instance, if you want to see all commits that are reachable from `refA` or `refB` but not from `refC`, you can type one of these:
224
+
225
+ $ git log refA refB ^refC
226
+ $ git log refA refB --not refC
227
+
228
+ This makes for a very powerful revision query system that should help you figure out what is in your branches.
229
+
230
+ #### Triple Dot ####
231
+
232
+ The last major range-selection syntax is the triple-dot syntax, which specifies all the commits that are reachable by either of two references but not by both of them. Look back at the example commit history in Figure 6-1.
233
+ If you want to see what is in `master` or `experiment` but not any common references, you can run
234
+
235
+ $ git log master...experiment
236
+ F
237
+ E
238
+ D
239
+ C
240
+
241
+ Again, this gives you normal `log` output but shows you only the commit information for those four commits, appearing in the traditional commit date ordering.
242
+
243
+ A common switch to use with the `log` command in this case is `--left-right`, which shows you which side of the range each commit is in. This helps make the data more useful:
244
+
245
+ $ git log --left-right master...experiment
246
+ < F
247
+ < E
248
+ > D
249
+ > C
250
+
251
+ With these tools, you can much more easily let Git know what commit or commits you want to inspect.
252
+
253
+ ## Interactive Staging ##
254
+
255
+ Git comes with a couple of scripts that make some command-line tasks easier. Here, you’ll look at a few interactive commands that can help you easily craft your commits to include only certain combinations and parts of files. These tools are very helpful if you modify a bunch of files and then decide that you want those changes to be in several focused commits rather than one big messy commit. This way, you can make sure your commits are logically separate changesets and can be easily reviewed by the developers working with you.
256
+ If you run `git add` with the `-i` or `--interactive` option, Git goes into an interactive shell mode, displaying something like this:
257
+
258
+ $ git add -i
259
+ staged unstaged path
260
+ 1: unchanged +0/-1 TODO
261
+ 2: unchanged +1/-1 index.html
262
+ 3: unchanged +5/-1 lib/simplegit.rb
263
+
264
+ *** Commands ***
265
+ 1: status 2: update 3: revert 4: add untracked
266
+ 5: patch 6: diff 7: quit 8: help
267
+ What now>
268
+
269
+ You can see that this command shows you a much different view of your staging area — basically the same information you get with `git status` but a bit more succinct and informative. It lists the changes you’ve staged on the left and unstaged changes on the right.
270
+
271
+ After this comes a Commands section. Here you can do a number of things, including staging files, unstaging files, staging parts of files, adding untracked files, and seeing diffs of what has been staged.
272
+
273
+ ### Staging and Unstaging Files ###
274
+
275
+ If you type `2` or `u` at the `What now>` prompt, the script prompts you for which files you want to stage:
276
+
277
+ What now> 2
278
+ staged unstaged path
279
+ 1: unchanged +0/-1 TODO
280
+ 2: unchanged +1/-1 index.html
281
+ 3: unchanged +5/-1 lib/simplegit.rb
282
+ Update>>
283
+
284
+ To stage the TODO and index.html files, you can type the numbers:
285
+
286
+ Update>> 1,2
287
+ staged unstaged path
288
+ * 1: unchanged +0/-1 TODO
289
+ * 2: unchanged +1/-1 index.html
290
+ 3: unchanged +5/-1 lib/simplegit.rb
291
+ Update>>
292
+
293
+ The `*` next to each file means the file is selected to be staged. If you press Enter after typing nothing at the `Update>>` prompt, Git takes anything selected and stages it for you:
294
+
295
+ Update>>
296
+ updated 2 paths
297
+
298
+ *** Commands ***
299
+ 1: status 2: update 3: revert 4: add untracked
300
+ 5: patch 6: diff 7: quit 8: help
301
+ What now> 1
302
+ staged unstaged path
303
+ 1: +0/-1 nothing TODO
304
+ 2: +1/-1 nothing index.html
305
+ 3: unchanged +5/-1 lib/simplegit.rb
306
+
307
+ Now you can see that the TODO and index.html files are staged and the simplegit.rb file is still unstaged. If you want to unstage the TODO file at this point, you use the `3` or `r` (for revert) option:
308
+
309
+ *** Commands ***
310
+ 1: status 2: update 3: revert 4: add untracked
311
+ 5: patch 6: diff 7: quit 8: help
312
+ What now> 3
313
+ staged unstaged path
314
+ 1: +0/-1 nothing TODO
315
+ 2: +1/-1 nothing index.html
316
+ 3: unchanged +5/-1 lib/simplegit.rb
317
+ Revert>> 1
318
+ staged unstaged path
319
+ * 1: +0/-1 nothing TODO
320
+ 2: +1/-1 nothing index.html
321
+ 3: unchanged +5/-1 lib/simplegit.rb
322
+ Revert>> [enter]
323
+ reverted one path
324
+
325
+ Looking at your Git status again, you can see that you’ve unstaged the TODO file:
326
+
327
+ *** Commands ***
328
+ 1: status 2: update 3: revert 4: add untracked
329
+ 5: patch 6: diff 7: quit 8: help
330
+ What now> 1
331
+ staged unstaged path
332
+ 1: unchanged +0/-1 TODO
333
+ 2: +1/-1 nothing index.html
334
+ 3: unchanged +5/-1 lib/simplegit.rb
335
+
336
+ To see the diff of what you’ve staged, you can use the `6` or `d` (for diff) command. It shows you a list of your staged files, and you can select the ones for which you would like to see the staged diff. This is much like specifying `git diff --cached` on the command line:
337
+
338
+ *** Commands ***
339
+ 1: status 2: update 3: revert 4: add untracked
340
+ 5: patch 6: diff 7: quit 8: help
341
+ What now> 6
342
+ staged unstaged path
343
+ 1: +1/-1 nothing index.html
344
+ Review diff>> 1
345
+ diff --git a/index.html b/index.html
346
+ index 4d07108..4335f49 100644
347
+ --- a/index.html
348
+ +++ b/index.html
349
+ @@ -16,7 +16,7 @@ Date Finder
350
+
351
+ <p id="out">...</p>
352
+
353
+ -<div id="footer">contact : support@github.com</div>
354
+ +<div id="footer">contact : email.support@github.com</div>
355
+
356
+ <script type="text/javascript">
357
+
358
+ With these basic commands, you can use the interactive add mode to deal with your staging area a little more easily.
359
+
360
+ ### Staging Patches ###
361
+
362
+ It’s also possible for Git to stage certain parts of files and not the rest. For example, if you make two changes to your simplegit.rb file and want to stage one of them and not the other, doing so is very easy in Git. From the interactive prompt, type `5` or `p` (for patch). Git will ask you which files you would like to partially stage; then, for each section of the selected files, it will display hunks of the file diff and ask if you would like to stage them, one by one:
363
+
364
+ diff --git a/lib/simplegit.rb b/lib/simplegit.rb
365
+ index dd5ecc4..57399e0 100644
366
+ --- a/lib/simplegit.rb
367
+ +++ b/lib/simplegit.rb
368
+ @@ -22,7 +22,7 @@ class SimpleGit
369
+ end
370
+
371
+ def log(treeish = 'master')
372
+ - command("git log -n 25 #{treeish}")
373
+ + command("git log -n 30 #{treeish}")
374
+ end
375
+
376
+ def blame(path)
377
+ Stage this hunk [y,n,a,d,/,j,J,g,e,?]?
378
+
379
+ You have a lot of options at this point. Typing `?` shows a list of what you can do:
380
+
381
+ Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
382
+ y - stage this hunk
383
+ n - do not stage this hunk
384
+ a - stage this and all the remaining hunks in the file
385
+ d - do not stage this hunk nor any of the remaining hunks in the file
386
+ g - select a hunk to go to
387
+ / - search for a hunk matching the given regex
388
+ j - leave this hunk undecided, see next undecided hunk
389
+ J - leave this hunk undecided, see next hunk
390
+ k - leave this hunk undecided, see previous undecided hunk
391
+ K - leave this hunk undecided, see previous hunk
392
+ s - split the current hunk into smaller hunks
393
+ e - manually edit the current hunk
394
+ ? - print help
395
+
396
+ Generally, you’ll type `y` or `n` if you want to stage each hunk, but staging all of them in certain files or skipping a hunk decision until later can be helpful too. If you stage one part of the file and leave another part unstaged, your status output will look like this:
397
+
398
+ What now> 1
399
+ staged unstaged path
400
+ 1: unchanged +0/-1 TODO
401
+ 2: +1/-1 nothing index.html
402
+ 3: +1/-1 +4/-0 lib/simplegit.rb
403
+
404
+ The status of the simplegit.rb file is interesting. It shows you that a couple of lines are staged and a couple are unstaged. You’ve partially staged this file. At this point, you can exit the interactive adding script and run `git commit` to commit the partially staged files.
405
+
406
+ Finally, you don’t need to be in interactive add mode to do the partial-file staging — you can start the same script by using `git add -p` or `git add --patch` on the command line.
407
+
408
+ ## Stashing ##
409
+
410
+ Often, when you’ve been working on part of your project, things are in a messy state and you want to switch branches for a bit to work on something else. The problem is, you don’t want to do a commit of half-done work just so you can get back to this point later. The answer to this issue is the `git stash` command.
411
+
412
+ Stashing takes the dirty state of your working directory — that is, your modified tracked files and staged changes — and saves it on a stack of unfinished changes that you can reapply at any time.
413
+
414
+ ### Stashing Your Work ###
415
+
416
+ To demonstrate, you’ll go into your project and start working on a couple of files and possibly stage one of the changes. If you run `git status`, you can see your dirty state:
417
+
418
+ $ git status
419
+ # On branch master
420
+ # Changes to be committed:
421
+ # (use "git reset HEAD <file>..." to unstage)
422
+ #
423
+ # modified: index.html
424
+ #
425
+ # Changes not staged for commit:
426
+ # (use "git add <file>..." to update what will be committed)
427
+ #
428
+ # modified: lib/simplegit.rb
429
+ #
430
+
431
+ Now you want to switch branches, but you don’t want to commit what you’ve been working on yet; so you’ll stash the changes. To push a new stash onto your stack, run `git stash`:
432
+
433
+ $ git stash
434
+ Saved working directory and index state \
435
+ "WIP on master: 049d078 added the index file"
436
+ HEAD is now at 049d078 added the index file
437
+ (To restore them type "git stash apply")
438
+
439
+ Your working directory is clean:
440
+
441
+ $ git status
442
+ # On branch master
443
+ nothing to commit, working directory clean
444
+
445
+ At this point, you can easily switch branches and do work elsewhere; your changes are stored on your stack. To see which stashes you’ve stored, you can use `git stash list`:
446
+
447
+ $ git stash list
448
+ stash@{0}: WIP on master: 049d078 added the index file
449
+ stash@{1}: WIP on master: c264051... Revert "added file_size"
450
+ stash@{2}: WIP on master: 21d80a5... added number to log
451
+
452
+ In this case, two stashes were done previously, so you have access to three different stashed works. You can reapply the one you just stashed by using the command shown in the help output of the original stash command: `git stash apply`. If you want to apply one of the older stashes, you can specify it by naming it, like this: `git stash apply stash@{2}`. If you don’t specify a stash, Git assumes the most recent stash and tries to apply it:
453
+
454
+ $ git stash apply
455
+ # On branch master
456
+ # Changes not staged for commit:
457
+ # (use "git add <file>..." to update what will be committed)
458
+ #
459
+ # modified: index.html
460
+ # modified: lib/simplegit.rb
461
+ #
462
+
463
+ You can see that Git re-modifies the files you uncommitted when you saved the stash. In this case, you had a clean working directory when you tried to apply the stash, and you tried to apply it on the same branch you saved it from; but having a clean working directory and applying it on the same branch aren’t necessary to successfully apply a stash. You can save a stash on one branch, switch to another branch later, and try to reapply the changes. You can also have modified and uncommitted files in your working directory when you apply a stash — Git gives you merge conflicts if anything no longer applies cleanly.
464
+
465
+ The changes to your files were reapplied, but the file you staged before wasn’t restaged. To do that, you must run the `git stash apply` command with a `--index` option to tell the command to try to reapply the staged changes. If you had run that instead, you’d have gotten back to your original position:
466
+
467
+ $ git stash apply --index
468
+ # On branch master
469
+ # Changes to be committed:
470
+ # (use "git reset HEAD <file>..." to unstage)
471
+ #
472
+ # modified: index.html
473
+ #
474
+ # Changes not staged for commit:
475
+ # (use "git add <file>..." to update what will be committed)
476
+ #
477
+ # modified: lib/simplegit.rb
478
+ #
479
+
480
+ The apply option only tries to apply the stashed work — you continue to have it on your stack. To remove it, you can run `git stash drop` with the name of the stash to remove:
481
+
482
+ $ git stash list
483
+ stash@{0}: WIP on master: 049d078 added the index file
484
+ stash@{1}: WIP on master: c264051... Revert "added file_size"
485
+ stash@{2}: WIP on master: 21d80a5... added number to log
486
+ $ git stash drop stash@{0}
487
+ Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
488
+
489
+ You can also run `git stash pop` to apply the stash and then immediately drop it from your stack.
490
+
491
+ ### Un-applying a Stash ###
492
+
493
+ In some use case scenarios you might want to apply stashed changes, do some work, but then un-apply those changes that originally came from the stash. Git does not provide such a `stash unapply` command, but it is possible to achieve the effect by simply retrieving the patch associated with a stash and applying it in reverse:
494
+
495
+ $ git stash show -p stash@{0} | git apply -R
496
+
497
+ Again, if you don’t specify a stash, Git assumes the most recent stash:
498
+
499
+ $ git stash show -p | git apply -R
500
+
501
+ You may want to create an alias and effectively add a `stash-unapply` command to your git. For example:
502
+
503
+ $ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
504
+ $ git stash apply
505
+ $ #... work work work
506
+ $ git stash-unapply
507
+
508
+ ### Creating a Branch from a Stash ###
509
+
510
+ If you stash some work, leave it there for a while, and continue on the branch from which you stashed the work, you may have a problem reapplying the work. If the apply tries to modify a file that you’ve since modified, you’ll get a merge conflict and will have to try to resolve it. If you want an easier way to test the stashed changes again, you can run `git stash branch`, which creates a new branch for you, checks out the commit you were on when you stashed your work, reapplies your work there, and then drops the stash if it applies successfully:
511
+
512
+ $ git stash branch testchanges
513
+ Switched to a new branch "testchanges"
514
+ # On branch testchanges
515
+ # Changes to be committed:
516
+ # (use "git reset HEAD <file>..." to unstage)
517
+ #
518
+ # modified: index.html
519
+ #
520
+ # Changes not staged for commit:
521
+ # (use "git add <file>..." to update what will be committed)
522
+ #
523
+ # modified: lib/simplegit.rb
524
+ #
525
+ Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
526
+
527
+ This is a nice shortcut to recover stashed work easily and work on it in a new branch.
528
+
529
+ ## Rewriting History ##
530
+
531
+ Many times, when working with Git, you may want to revise your commit history for some reason. One of the great things about Git is that it allows you to make decisions at the last possible moment. You can decide what files go into which commits right before you commit with the staging area, you can decide that you didn’t mean to be working on something yet with the stash command, and you can rewrite commits that already happened so they look like they happened in a different way. This can involve changing the order of the commits, changing messages or modifying files in a commit, squashing together or splitting apart commits, or removing commits entirely — all before you share your work with others.
532
+
533
+ In this section, you’ll cover how to accomplish these very useful tasks so that you can make your commit history look the way you want before you share it with others.
534
+
535
+ ### Changing the Last Commit ###
536
+
537
+ Changing your last commit is probably the most common rewriting of history that you’ll do. You’ll often want to do two basic things to your last commit: change the commit message, or change the snapshot you just recorded by adding, changing and removing files.
538
+
539
+ If you only want to modify your last commit message, it’s very simple:
540
+
541
+ $ git commit --amend
542
+
543
+ That drops you into your text editor, which has your last commit message in it, ready for you to modify the message. When you save and close the editor, the editor writes a new commit containing that message and makes it your new last commit.
544
+
545
+ If you’ve committed and then you want to change the snapshot you committed by adding or changing files, possibly because you forgot to add a newly created file when you originally committed, the process works basically the same way. You stage the changes you want by editing a file and running `git add` on it or `git rm` to a tracked file, and the subsequent `git commit --amend` takes your current staging area and makes it the snapshot for the new commit.
546
+
547
+ You need to be careful with this technique because amending changes the SHA-1 of the commit. It’s like a very small rebase — don’t amend your last commit if you’ve already pushed it.
548
+
549
+ ### Changing Multiple Commit Messages ###
550
+
551
+ To modify a commit that is farther back in your history, you must move to more complex tools. Git doesn’t have a modify-history tool, but you can use the rebase tool to rebase a series of commits onto the HEAD they were originally based on instead of moving them to another one. With the interactive rebase tool, you can then stop after each commit you want to modify and change the message, add files, or do whatever you wish. You can run rebase interactively by adding the `-i` option to `git rebase`. You must indicate how far back you want to rewrite commits by telling the command which commit to rebase onto.
552
+
553
+ For example, if you want to change the last three commit messages, or any of the commit messages in that group, you supply as an argument to `git rebase -i` the parent of the last commit you want to edit, which is `HEAD~2^` or `HEAD~3`. It may be easier to remember the `~3` because you’re trying to edit the last three commits; but keep in mind that you’re actually designating four commits ago, the parent of the last commit you want to edit:
554
+
555
+ $ git rebase -i HEAD~3
556
+
557
+ Remember again that this is a rebasing command — every commit included in the range `HEAD~3..HEAD` will be rewritten, whether you change the message or not. Don’t include any commit you’ve already pushed to a central server — doing so will confuse other developers by providing an alternate version of the same change.
558
+
559
+ Running this command gives you a list of commits in your text editor that looks something like this:
560
+
561
+ pick f7f3f6d changed my name a bit
562
+ pick 310154e updated README formatting and added blame
563
+ pick a5f4a0d added cat-file
564
+
565
+ # Rebase 710f0f8..a5f4a0d onto 710f0f8
566
+ #
567
+ # Commands:
568
+ # p, pick = use commit
569
+ # e, edit = use commit, but stop for amending
570
+ # s, squash = use commit, but meld into previous commit
571
+ #
572
+ # If you remove a line here THAT COMMIT WILL BE LOST.
573
+ # However, if you remove everything, the rebase will be aborted.
574
+ #
575
+
576
+ It’s important to note that these commits are listed in the opposite order than you normally see them using the `log` command. If you run a `log`, you see something like this:
577
+
578
+ $ git log --pretty=format:"%h %s" HEAD~3..HEAD
579
+ a5f4a0d added cat-file
580
+ 310154e updated README formatting and added blame
581
+ f7f3f6d changed my name a bit
582
+
583
+ Notice the reverse order. The interactive rebase gives you a script that it’s going to run. It will start at the commit you specify on the command line (`HEAD~3`) and replay the changes introduced in each of these commits from top to bottom. It lists the oldest at the top, rather than the newest, because that’s the first one it will replay.
584
+
585
+ You need to edit the script so that it stops at the commit you want to edit. To do so, change the word pick to the word edit for each of the commits you want the script to stop after. For example, to modify only the third commit message, you change the file to look like this:
586
+
587
+ edit f7f3f6d changed my name a bit
588
+ pick 310154e updated README formatting and added blame
589
+ pick a5f4a0d added cat-file
590
+
591
+ When you save and exit the editor, Git rewinds you back to the last commit in that list and drops you on the command line with the following message:
592
+
593
+ $ git rebase -i HEAD~3
594
+ Stopped at 7482e0d... updated the gemspec to hopefully work better
595
+ You can amend the commit now, with
596
+
597
+ git commit --amend
598
+
599
+ Once you’re satisfied with your changes, run
600
+
601
+ git rebase --continue
602
+
603
+ These instructions tell you exactly what to do. Type
604
+
605
+ $ git commit --amend
606
+
607
+ Change the commit message, and exit the editor. Then, run
608
+
609
+ $ git rebase --continue
610
+
611
+ This command will apply the other two commits automatically, and then you’re done. If you change pick to edit on more lines, you can repeat these steps for each commit you change to edit. Each time, Git will stop, let you amend the commit, and continue when you’re finished.
612
+
613
+ ### Reordering Commits ###
614
+
615
+ You can also use interactive rebases to reorder or remove commits entirely. If you want to remove the "added cat-file" commit and change the order in which the other two commits are introduced, you can change the rebase script from this
616
+
617
+ pick f7f3f6d changed my name a bit
618
+ pick 310154e updated README formatting and added blame
619
+ pick a5f4a0d added cat-file
620
+
621
+ to this:
622
+
623
+ pick 310154e updated README formatting and added blame
624
+ pick f7f3f6d changed my name a bit
625
+
626
+ When you save and exit the editor, Git rewinds your branch to the parent of these commits, applies `310154e` and then `f7f3f6d`, and then stops. You effectively change the order of those commits and remove the "added cat-file" commit completely.
627
+
628
+ ### Squashing Commits ###
629
+
630
+ It’s also possible to take a series of commits and squash them down into a single commit with the interactive rebasing tool. The script puts helpful instructions in the rebase message:
631
+
632
+ #
633
+ # Commands:
634
+ # p, pick = use commit
635
+ # e, edit = use commit, but stop for amending
636
+ # s, squash = use commit, but meld into previous commit
637
+ #
638
+ # If you remove a line here THAT COMMIT WILL BE LOST.
639
+ # However, if you remove everything, the rebase will be aborted.
640
+ #
641
+
642
+ If, instead of "pick" or "edit", you specify "squash", Git applies both that change and the change directly before it and makes you merge the commit messages together. So, if you want to make a single commit from these three commits, you make the script look like this:
643
+
644
+ pick f7f3f6d changed my name a bit
645
+ squash 310154e updated README formatting and added blame
646
+ squash a5f4a0d added cat-file
647
+
648
+ When you save and exit the editor, Git applies all three changes and then puts you back into the editor to merge the three commit messages:
649
+
650
+ # This is a combination of 3 commits.
651
+ # The first commit's message is:
652
+ changed my name a bit
653
+
654
+ # This is the 2nd commit message:
655
+
656
+ updated README formatting and added blame
657
+
658
+ # This is the 3rd commit message:
659
+
660
+ added cat-file
661
+
662
+ When you save that, you have a single commit that introduces the changes of all three previous commits.
663
+
664
+ ### Splitting a Commit ###
665
+
666
+ Splitting a commit undoes a commit and then partially stages and commits as many times as commits you want to end up with. For example, suppose you want to split the middle commit of your three commits. Instead of "updated README formatting and added blame", you want to split it into two commits: "updated README formatting" for the first, and "added blame" for the second. You can do that in the `rebase -i` script by changing the instruction on the commit you want to split to "edit":
667
+
668
+ pick f7f3f6d changed my name a bit
669
+ edit 310154e updated README formatting and added blame
670
+ pick a5f4a0d added cat-file
671
+
672
+ Then, when the script drops you to the command line, you reset that commit, take the changes that have been reset, and create multiple commits out of them. When you save and exit the editor, Git rewinds to the parent of the first commit in your list, applies the first commit (`f7f3f6d`), applies the second (`310154e`), and drops you to the console. There, you can do a mixed reset of that commit with `git reset HEAD^`, which effectively undoes that commit and leaves the modified files unstaged. Now you can stage and commit files until you have several commits, and run `git rebase --continue` when you’re done:
673
+
674
+ $ git reset HEAD^
675
+ $ git add README
676
+ $ git commit -m 'updated README formatting'
677
+ $ git add lib/simplegit.rb
678
+ $ git commit -m 'added blame'
679
+ $ git rebase --continue
680
+
681
+ Git applies the last commit (`a5f4a0d`) in the script, and your history looks like this:
682
+
683
+ $ git log -4 --pretty=format:"%h %s"
684
+ 1c002dd added cat-file
685
+ 9b29157 added blame
686
+ 35cfb2b updated README formatting
687
+ f3cc40e changed my name a bit
688
+
689
+ Once again, this changes the SHAs of all the commits in your list, so make sure no commit shows up in that list that you’ve already pushed to a shared repository.
690
+
691
+ ### The Nuclear Option: filter-branch ###
692
+
693
+ There is another history-rewriting option that you can use if you need to rewrite a larger number of commits in some scriptable way — for instance, changing your e-mail address globally or removing a file from every commit. The command is `filter-branch`, and it can rewrite huge swaths of your history, so you probably shouldn’t use it unless your project isn’t yet public and other people haven’t based work off the commits you’re about to rewrite. However, it can be very useful. You’ll learn a few of the common uses so you can get an idea of some of the things it’s capable of.
694
+
695
+ #### Removing a File from Every Commit ####
696
+
697
+ This occurs fairly commonly. Someone accidentally commits a huge binary file with a thoughtless `git add .`, and you want to remove it everywhere. Perhaps you accidentally committed a file that contained a password, and you want to make your project open source. `filter-branch` is the tool you probably want to use to scrub your entire history. To remove a file named passwords.txt from your entire history, you can use the `--tree-filter` option to `filter-branch`:
698
+
699
+ $ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
700
+ Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21)
701
+ Ref 'refs/heads/master' was rewritten
702
+
703
+ The `--tree-filter` option runs the specified command after each checkout of the project and then recommits the results. In this case, you remove a file called passwords.txt from every snapshot, whether it exists or not. If you want to remove all accidentally committed editor backup files, you can run something like `git filter-branch --tree-filter "find * -type f -name '*~' -delete" HEAD`.
704
+
705
+ You’ll be able to watch Git rewriting trees and commits and then move the branch pointer at the end. It’s generally a good idea to do this in a testing branch and then hard-reset your master branch after you’ve determined the outcome is what you really want. To run `filter-branch` on all your branches, you can pass `--all` to the command.
706
+
707
+ #### Making a Subdirectory the New Root ####
708
+
709
+ Suppose you’ve done an import from another source control system and have subdirectories that make no sense (trunk, tags, and so on). If you want to make the `trunk` subdirectory be the new project root for every commit, `filter-branch` can help you do that, too:
710
+
711
+ $ git filter-branch --subdirectory-filter trunk HEAD
712
+ Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12)
713
+ Ref 'refs/heads/master' was rewritten
714
+
715
+ Now your new project root is what was in the `trunk` subdirectory each time. Git will also automatically remove commits that did not affect the subdirectory.
716
+
717
+ #### Changing E-Mail Addresses Globally ####
718
+
719
+ Another common case is that you forgot to run `git config` to set your name and e-mail address before you started working, or perhaps you want to open-source a project at work and change all your work e-mail addresses to your personal address. In any case, you can change e-mail addresses in multiple commits in a batch with `filter-branch` as well. You need to be careful to change only the e-mail addresses that are yours, so you use `--commit-filter`:
720
+
721
+ $ git filter-branch --commit-filter '
722
+ if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
723
+ then
724
+ GIT_AUTHOR_NAME="Scott Chacon";
725
+ GIT_AUTHOR_EMAIL="schacon@example.com";
726
+ git commit-tree "$@";
727
+ else
728
+ git commit-tree "$@";
729
+ fi' HEAD
730
+
731
+ This goes through and rewrites every commit to have your new address. Because commits contain the SHA-1 values of their parents, this command changes every commit SHA in your history, not just those that have the matching e-mail address.
732
+
733
+ ## Debugging with Git ##
734
+
735
+ Git also provides a couple of tools to help you debug issues in your projects. Because Git is designed to work with nearly any type of project, these tools are pretty generic, but they can often help you hunt for a bug or culprit when things go wrong.
736
+
737
+ ### File Annotation ###
738
+
739
+ If you track down a bug in your code and want to know when it was introduced and why, file annotation is often your best tool. It shows you what commit was the last to modify each line of any file. So, if you see that a method in your code is buggy, you can annotate the file with `git blame` to see when each line of the method was last edited and by whom. This example uses the `-L` option to limit the output to lines 12 through 22:
740
+
741
+ $ git blame -L 12,22 simplegit.rb
742
+ ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 12) def show(tree = 'master')
743
+ ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 13) command("git show #{tree}")
744
+ ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 14) end
745
+ ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 15)
746
+ 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 16) def log(tree = 'master')
747
+ 79eaf55d (Scott Chacon 2008-04-06 10:15:08 -0700 17) command("git log #{tree}")
748
+ 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 18) end
749
+ 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 19)
750
+ 42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 20) def blame(path)
751
+ 42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 21) command("git blame #{path}")
752
+ 42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 22) end
753
+
754
+ Notice that the first field is the partial SHA-1 of the commit that last modified that line. The next two fields are values extracted from that commit—the author name and the authored date of that commit — so you can easily see who modified that line and when. After that come the line number and the content of the file. Also note the `^4832fe2` commit lines, which designate that those lines were in this file’s original commit. That commit is when this file was first added to this project, and those lines have been unchanged since. This is a tad confusing, because now you’ve seen at least three different ways that Git uses the `^` to modify a commit SHA, but that is what it means here.
755
+
756
+ Another cool thing about Git is that it doesn’t track file renames explicitly. It records the snapshots and then tries to figure out what was renamed implicitly, after the fact. One of the interesting features of this is that you can ask it to figure out all sorts of code movement as well. If you pass `-C` to `git blame`, Git analyzes the file you’re annotating and tries to figure out where snippets of code within it originally came from if they were copied from elsewhere. Recently, I was refactoring a file named `GITServerHandler.m` into multiple files, one of which was `GITPackUpload.m`. By blaming `GITPackUpload.m` with the `-C` option, I could see where sections of the code originally came from:
757
+
758
+ $ git blame -C -L 141,153 GITPackUpload.m
759
+ f344f58d GITServerHandler.m (Scott 2009-01-04 141)
760
+ f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC
761
+ f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
762
+ 70befddd GITServerHandler.m (Scott 2009-03-22 144) //NSLog(@"GATHER COMMI
763
+ ad11ac80 GITPackUpload.m (Scott 2009-03-24 145)
764
+ ad11ac80 GITPackUpload.m (Scott 2009-03-24 146) NSString *parentSha;
765
+ ad11ac80 GITPackUpload.m (Scott 2009-03-24 147) GITCommit *commit = [g
766
+ ad11ac80 GITPackUpload.m (Scott 2009-03-24 148)
767
+ ad11ac80 GITPackUpload.m (Scott 2009-03-24 149) //NSLog(@"GATHER COMMI
768
+ ad11ac80 GITPackUpload.m (Scott 2009-03-24 150)
769
+ 56ef2caf GITServerHandler.m (Scott 2009-01-05 151) if(commit) {
770
+ 56ef2caf GITServerHandler.m (Scott 2009-01-05 152) [refDict setOb
771
+ 56ef2caf GITServerHandler.m (Scott 2009-01-05 153)
772
+
773
+ This is really useful. Normally, you get as the original commit the commit where you copied the code over, because that is the first time you touched those lines in this file. Git tells you the original commit where you wrote those lines, even if it was in another file.
774
+
775
+ ### Binary Search ###
776
+
777
+ Annotating a file helps if you know where the issue is to begin with. If you don’t know what is breaking, and there have been dozens or hundreds of commits since the last state where you know the code worked, you’ll likely turn to `git bisect` for help. The `bisect` command does a binary search through your commit history to help you identify as quickly as possible which commit introduced an issue.
778
+
779
+ Let’s say you just pushed out a release of your code to a production environment, you’re getting bug reports about something that wasn’t happening in your development environment, and you can’t imagine why the code is doing that. You go back to your code, and it turns out you can reproduce the issue, but you can’t figure out what is going wrong. You can bisect the code to find out. First you run `git bisect start` to get things going, and then you use `git bisect bad` to tell the system that the current commit you’re on is broken. Then, you must tell bisect when the last known good state was, using `git bisect good [good_commit]`:
780
+
781
+ $ git bisect start
782
+ $ git bisect bad
783
+ $ git bisect good v1.0
784
+ Bisecting: 6 revisions left to test after this
785
+ [ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] error handling on repo
786
+
787
+ Git figured out that about 12 commits came between the commit you marked as the last good commit (v1.0) and the current bad version, and it checked out the middle one for you. At this point, you can run your test to see if the issue exists as of this commit. If it does, then it was introduced sometime before this middle commit; if it doesn’t, then the problem was introduced sometime after the middle commit. It turns out there is no issue here, and you tell Git that by typing `git bisect good` and continue your journey:
788
+
789
+ $ git bisect good
790
+ Bisecting: 3 revisions left to test after this
791
+ [b047b02ea83310a70fd603dc8cd7a6cd13d15c04] secure this thing
792
+
793
+ Now you’re on another commit, halfway between the one you just tested and your bad commit. You run your test again and find that this commit is broken, so you tell Git that with `git bisect bad`:
794
+
795
+ $ git bisect bad
796
+ Bisecting: 1 revisions left to test after this
797
+ [f71ce38690acf49c1f3c9bea38e09d82a5ce6014] drop exceptions table
798
+
799
+ This commit is fine, and now Git has all the information it needs to determine where the issue was introduced. It tells you the SHA-1 of the first bad commit and show some of the commit information and which files were modified in that commit so you can figure out what happened that may have introduced this bug:
800
+
801
+ $ git bisect good
802
+ b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
803
+ commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
804
+ Author: PJ Hyett <pjhyett@example.com>
805
+ Date: Tue Jan 27 14:48:32 2009 -0800
806
+
807
+ secure this thing
808
+
809
+ :040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
810
+ f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M config
811
+
812
+ When you’re finished, you should run `git bisect reset` to reset your HEAD to where you were before you started, or you’ll end up in a weird state:
813
+
814
+ $ git bisect reset
815
+
816
+ This is a powerful tool that can help you check hundreds of commits for an introduced bug in minutes. In fact, if you have a script that will exit 0 if the project is good or non-0 if the project is bad, you can fully automate `git bisect`. First, you again tell it the scope of the bisect by providing the known bad and good commits. You can do this by listing them with the `bisect start` command if you want, listing the known bad commit first and the known good commit second:
817
+
818
+ $ git bisect start HEAD v1.0
819
+ $ git bisect run test-error.sh
820
+
821
+ Doing so automatically runs `test-error.sh` on each checked-out commit until Git finds the first broken commit. You can also run something like `make` or `make tests` or whatever you have that runs automated tests for you.
822
+
823
+ ## Submodules ##
824
+
825
+ It often happens that while working on one project, you need to use another project from within it. Perhaps it’s a library that a third party developed or that you’re developing separately and using in multiple parent projects. A common issue arises in these scenarios: you want to be able to treat the two projects as separate yet still be able to use one from within the other.
826
+
827
+ Here’s an example. Suppose you’re developing a web site and creating Atom feeds. Instead of writing your own Atom-generating code, you decide to use a library. You’re likely to have to either include this code from a shared library like a CPAN install or Ruby gem, or copy the source code into your own project tree. The issue with including the library is that it’s difficult to customize the library in any way and often more difficult to deploy it, because you need to make sure every client has that library available. The issue with vendoring the code into your own project is that any custom changes you make are difficult to merge when upstream changes become available.
828
+
829
+ Git addresses this issue using submodules. Submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.
830
+
831
+ ### Starting with Submodules ###
832
+
833
+ Suppose you want to add the Rack library (a Ruby web server gateway interface) to your project, possibly maintain your own changes to it, but continue to merge in upstream changes. The first thing you should do is clone the external repository into your subdirectory. You add external projects as submodules with the `git submodule add` command:
834
+
835
+ $ git submodule add git://github.com/chneukirchen/rack.git rack
836
+ Initialized empty Git repository in /opt/subtest/rack/.git/
837
+ remote: Counting objects: 3181, done.
838
+ remote: Compressing objects: 100% (1534/1534), done.
839
+ remote: Total 3181 (delta 1951), reused 2623 (delta 1603)
840
+ Receiving objects: 100% (3181/3181), 675.42 KiB | 422 KiB/s, done.
841
+ Resolving deltas: 100% (1951/1951), done.
842
+
843
+ Now you have the Rack project under a subdirectory named `rack` within your project. You can go into that subdirectory, make changes, add your own writable remote repository to push your changes into, fetch and merge from the original repository, and more. If you run `git status` right after you add the submodule, you see two things:
844
+
845
+ $ git status
846
+ # On branch master
847
+ # Changes to be committed:
848
+ # (use "git reset HEAD <file>..." to unstage)
849
+ #
850
+ # new file: .gitmodules
851
+ # new file: rack
852
+ #
853
+
854
+ First you notice the `.gitmodules` file. This is a configuration file that stores the mapping between the project’s URL and the local subdirectory you’ve pulled it into:
855
+
856
+ $ cat .gitmodules
857
+ [submodule "rack"]
858
+ path = rack
859
+ url = git://github.com/chneukirchen/rack.git
860
+
861
+ If you have multiple submodules, you’ll have multiple entries in this file. It’s important to note that this file is version-controlled with your other files, like your `.gitignore` file. It’s pushed and pulled with the rest of your project. This is how other people who clone this project know where to get the submodule projects from.
862
+
863
+ The other listing in the `git status` output is the rack entry. If you run `git diff` on that, you see something interesting:
864
+
865
+ $ git diff --cached rack
866
+ diff --git a/rack b/rack
867
+ new file mode 160000
868
+ index 0000000..08d709f
869
+ --- /dev/null
870
+ +++ b/rack
871
+ @@ -0,0 +1 @@
872
+ +Subproject commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
873
+
874
+ Although `rack` is a subdirectory in your working directory, Git sees it as a submodule and doesn’t track its contents when you’re not in that directory. Instead, Git records it as a particular commit from that repository. When you make changes and commit in that subdirectory, the superproject notices that the HEAD there has changed and records the exact commit you’re currently working off of; that way, when others clone this project, they can re-create the environment exactly.
875
+
876
+ This is an important point with submodules: you record them as the exact commit they’re at. You can’t record a submodule at `master` or some other symbolic reference.
877
+
878
+ When you commit, you see something like this:
879
+
880
+ $ git commit -m 'first commit with submodule rack'
881
+ [master 0550271] first commit with submodule rack
882
+ 2 files changed, 4 insertions(+), 0 deletions(-)
883
+ create mode 100644 .gitmodules
884
+ create mode 160000 rack
885
+
886
+ Notice the 160000 mode for the rack entry. That is a special mode in Git that basically means you’re recording a commit as a directory entry rather than a subdirectory or a file.
887
+
888
+ You can treat the `rack` directory as a separate project and then update your superproject from time to time with a pointer to the latest commit in that subproject. All the Git commands work independently in the two directories:
889
+
890
+ $ git log -1
891
+ commit 0550271328a0038865aad6331e620cd7238601bb
892
+ Author: Scott Chacon <schacon@gmail.com>
893
+ Date: Thu Apr 9 09:03:56 2009 -0700
894
+
895
+ first commit with submodule rack
896
+ $ cd rack/
897
+ $ git log -1
898
+ commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
899
+ Author: Christian Neukirchen <chneukirchen@gmail.com>
900
+ Date: Wed Mar 25 14:49:04 2009 +0100
901
+
902
+ Document version change
903
+
904
+ ### Cloning a Project with Submodules ###
905
+
906
+ Here you’ll clone a project with a submodule in it. When you receive such a project, you get the directories that contain submodules, but none of the files yet:
907
+
908
+ $ git clone git://github.com/schacon/myproject.git
909
+ Initialized empty Git repository in /opt/myproject/.git/
910
+ remote: Counting objects: 6, done.
911
+ remote: Compressing objects: 100% (4/4), done.
912
+ remote: Total 6 (delta 0), reused 0 (delta 0)
913
+ Receiving objects: 100% (6/6), done.
914
+ $ cd myproject
915
+ $ ls -l
916
+ total 8
917
+ -rw-r--r-- 1 schacon admin 3 Apr 9 09:11 README
918
+ drwxr-xr-x 2 schacon admin 68 Apr 9 09:11 rack
919
+ $ ls rack/
920
+ $
921
+
922
+ The `rack` directory is there, but empty. You must run two commands: `git submodule init` to initialize your local configuration file, and `git submodule update` to fetch all the data from that project and check out the appropriate commit listed in your superproject:
923
+
924
+ $ git submodule init
925
+ Submodule 'rack' (git://github.com/chneukirchen/rack.git) registered for path 'rack'
926
+ $ git submodule update
927
+ Initialized empty Git repository in /opt/myproject/rack/.git/
928
+ remote: Counting objects: 3181, done.
929
+ remote: Compressing objects: 100% (1534/1534), done.
930
+ remote: Total 3181 (delta 1951), reused 2623 (delta 1603)
931
+ Receiving objects: 100% (3181/3181), 675.42 KiB | 173 KiB/s, done.
932
+ Resolving deltas: 100% (1951/1951), done.
933
+ Submodule path 'rack': checked out '08d709f78b8c5b0fbeb7821e37fa53e69afcf433'
934
+
935
+ Now your `rack` subdirectory is at the exact state it was in when you committed earlier. If another developer makes changes to the rack code and commits, and you pull that reference down and merge it in, you get something a bit odd:
936
+
937
+ $ git merge origin/master
938
+ Updating 0550271..85a3eee
939
+ Fast forward
940
+ rack | 2 +-
941
+ 1 files changed, 1 insertions(+), 1 deletions(-)
942
+ [master*]$ git status
943
+ # On branch master
944
+ # Changes not staged for commit:
945
+ # (use "git add <file>..." to update what will be committed)
946
+ # (use "git checkout -- <file>..." to discard changes in working directory)
947
+ #
948
+ # modified: rack
949
+ #
950
+
951
+ You merged in what is basically a change to the pointer for your submodule; but it doesn’t update the code in the submodule directory, so it looks like you have a dirty state in your working directory:
952
+
953
+ $ git diff
954
+ diff --git a/rack b/rack
955
+ index 6c5e70b..08d709f 160000
956
+ --- a/rack
957
+ +++ b/rack
958
+ @@ -1 +1 @@
959
+ -Subproject commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
960
+ +Subproject commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
961
+
962
+ This is the case because the pointer you have for the submodule isn’t what is actually in the submodule directory. To fix this, you must run `git submodule update` again:
963
+
964
+ $ git submodule update
965
+ remote: Counting objects: 5, done.
966
+ remote: Compressing objects: 100% (3/3), done.
967
+ remote: Total 3 (delta 1), reused 2 (delta 0)
968
+ Unpacking objects: 100% (3/3), done.
969
+ From git@github.com:schacon/rack
970
+ 08d709f..6c5e70b master -> origin/master
971
+ Submodule path 'rack': checked out '6c5e70b984a60b3cecd395edd5b48a7575bf58e0'
972
+
973
+ You have to do this every time you pull down a submodule change in the main project. It’s strange, but it works.
974
+
975
+ One common problem happens when a developer makes a change locally in a submodule but doesn’t push it to a public server. Then, they commit a pointer to that non-public state and push up the superproject. When other developers try to run `git submodule update`, the submodule system can’t find the commit that is referenced, because it exists only on the first developer’s system. If that happens, you see an error like this:
976
+
977
+ $ git submodule update
978
+ fatal: reference isn’t a tree: 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
979
+ Unable to checkout '6c5e70b984a60b3cecd395edd5ba7575bf58e0' in submodule path 'rack'
980
+
981
+ You have to see who last changed the submodule:
982
+
983
+ $ git log -1 rack
984
+ commit 85a3eee996800fcfa91e2119372dd4172bf76678
985
+ Author: Scott Chacon <schacon@gmail.com>
986
+ Date: Thu Apr 9 09:19:14 2009 -0700
987
+
988
+ added a submodule reference I will never make public. hahahahaha!
989
+
990
+ Then, you e-mail that guy and yell at him.
991
+
992
+ ### Superprojects ###
993
+
994
+ Sometimes, developers want to get a combination of a large project’s subdirectories, depending on what team they’re on. This is common if you’re coming from CVS or Subversion, where you’ve defined a module or collection of subdirectories, and you want to keep this type of workflow.
995
+
996
+ A good way to do this in Git is to make each of the subfolders a separate Git repository and then create superproject Git repositories that contain multiple submodules. A benefit of this approach is that you can more specifically define the relationships between the projects with tags and branches in the superprojects.
997
+
998
+ ### Issues with Submodules ###
999
+
1000
+ Using submodules isn’t without hiccups, however. First, you must be relatively careful when working in the submodule directory. When you run `git submodule update`, it checks out the specific version of the project, but not within a branch. This is called having a detached HEAD — it means the HEAD file points directly to a commit, not to a symbolic reference. The issue is that you generally don’t want to work in a detached HEAD environment, because it’s easy to lose changes. If you do an initial `submodule update`, commit in that submodule directory without creating a branch to work in, and then run `git submodule update` again from the superproject without committing in the meantime, Git will overwrite your changes without telling you. Technically you won’t lose the work, but you won’t have a branch pointing to it, so it will be somewhat difficult to retrieve.
1001
+
1002
+ To avoid this issue, create a branch when you work in a submodule directory with `git checkout -b work` or something equivalent. When you do the submodule update a second time, it will still revert your work, but at least you have a pointer to get back to.
1003
+
1004
+ Switching branches with submodules in them can also be tricky. If you create a new branch, add a submodule there, and then switch back to a branch without that submodule, you still have the submodule directory as an untracked directory:
1005
+
1006
+ $ git checkout -b rack
1007
+ Switched to a new branch "rack"
1008
+ $ git submodule add git@github.com:schacon/rack.git rack
1009
+ Initialized empty Git repository in /opt/myproj/rack/.git/
1010
+ ...
1011
+ Receiving objects: 100% (3184/3184), 677.42 KiB | 34 KiB/s, done.
1012
+ Resolving deltas: 100% (1952/1952), done.
1013
+ $ git commit -am 'added rack submodule'
1014
+ [rack cc49a69] added rack submodule
1015
+ 2 files changed, 4 insertions(+), 0 deletions(-)
1016
+ create mode 100644 .gitmodules
1017
+ create mode 160000 rack
1018
+ $ git checkout master
1019
+ Switched to branch "master"
1020
+ $ git status
1021
+ # On branch master
1022
+ # Untracked files:
1023
+ # (use "git add <file>..." to include in what will be committed)
1024
+ #
1025
+ # rack/
1026
+
1027
+ You have to either move it out of the way or remove it, in which case you have to clone it again when you switch back—and you may lose local changes or branches that you didn’t push up.
1028
+
1029
+ The last main caveat that many people run into involves switching from subdirectories to submodules. If you’ve been tracking files in your project and you want to move them out into a submodule, you must be careful or Git will get angry at you. Assume that you have the rack files in a subdirectory of your project, and you want to switch it to a submodule. If you delete the subdirectory and then run `submodule add`, Git yells at you:
1030
+
1031
+ $ rm -Rf rack/
1032
+ $ git submodule add git@github.com:schacon/rack.git rack
1033
+ 'rack' already exists in the index
1034
+
1035
+ You have to unstage the `rack` directory first. Then you can add the submodule:
1036
+
1037
+ $ git rm -r rack
1038
+ $ git submodule add git@github.com:schacon/rack.git rack
1039
+ Initialized empty Git repository in /opt/testsub/rack/.git/
1040
+ remote: Counting objects: 3184, done.
1041
+ remote: Compressing objects: 100% (1465/1465), done.
1042
+ remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
1043
+ Receiving objects: 100% (3184/3184), 677.42 KiB | 88 KiB/s, done.
1044
+ Resolving deltas: 100% (1952/1952), done.
1045
+
1046
+ Now suppose you did that in a branch. If you try to switch back to a branch where those files are still in the actual tree rather than a submodule — you get this error:
1047
+
1048
+ $ git checkout master
1049
+ error: Untracked working tree file 'rack/AUTHORS' would be overwritten by merge.
1050
+
1051
+ You have to move the `rack` submodule directory out of the way before you can switch to a branch that doesn’t have it:
1052
+
1053
+ $ mv rack /tmp/
1054
+ $ git checkout master
1055
+ Switched to branch "master"
1056
+ $ ls
1057
+ README rack
1058
+
1059
+ Then, when you switch back, you get an empty `rack` directory. You can either run `git submodule update` to reclone, or you can move your `/tmp/rack` directory back into the empty directory.
1060
+
1061
+ ## Subtree Merging ##
1062
+
1063
+ Now that you’ve seen the difficulties of the submodule system, let’s look at an alternate way to solve the same problem. When Git merges, it looks at what it has to merge together and then chooses an appropriate merging strategy to use. If you’re merging two branches, Git uses a _recursive_ strategy. If you’re merging more than two branches, Git picks the _octopus_ strategy. These strategies are automatically chosen for you because the recursive strategy can handle complex three-way merge situations — for example, more than one common ancestor — but it can only handle merging two branches. The octopus merge can handle multiple branches but is more cautious to avoid difficult conflicts, so it’s chosen as the default strategy if you’re trying to merge more than two branches.
1064
+
1065
+ However, there are other strategies you can choose as well. One of them is the _subtree_ merge, and you can use it to deal with the subproject issue. Here you’ll see how to do the same rack embedding as in the last section, but using subtree merges instead.
1066
+
1067
+ The idea of the subtree merge is that you have two projects, and one of the projects maps to a subdirectory of the other one and vice versa. When you specify a subtree merge, Git is smart enough to figure out that one is a subtree of the other and merge appropriately — it’s pretty amazing.
1068
+
1069
+ You first add the Rack application to your project. You add the Rack project as a remote reference in your own project and then check it out into its own branch:
1070
+
1071
+ $ git remote add rack_remote git@github.com:schacon/rack.git
1072
+ $ git fetch rack_remote
1073
+ warning: no common commits
1074
+ remote: Counting objects: 3184, done.
1075
+ remote: Compressing objects: 100% (1465/1465), done.
1076
+ remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
1077
+ Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
1078
+ Resolving deltas: 100% (1952/1952), done.
1079
+ From git@github.com:schacon/rack
1080
+ * [new branch] build -> rack_remote/build
1081
+ * [new branch] master -> rack_remote/master
1082
+ * [new branch] rack-0.4 -> rack_remote/rack-0.4
1083
+ * [new branch] rack-0.9 -> rack_remote/rack-0.9
1084
+ $ git checkout -b rack_branch rack_remote/master
1085
+ Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
1086
+ Switched to a new branch "rack_branch"
1087
+
1088
+ Now you have the root of the Rack project in your `rack_branch` branch and your own project in the `master` branch. If you check out one and then the other, you can see that they have different project roots:
1089
+
1090
+ $ ls
1091
+ AUTHORS KNOWN-ISSUES Rakefile contrib lib
1092
+ COPYING README bin example test
1093
+ $ git checkout master
1094
+ Switched to branch "master"
1095
+ $ ls
1096
+ README
1097
+
1098
+ You want to pull the Rack project into your `master` project as a subdirectory. You can do that in Git with `git read-tree`. You’ll learn more about `read-tree` and its friends in Chapter 9, but for now know that it reads the root tree of one branch into your current staging area and working directory. You just switched back to your `master` branch, and you pull the `rack_branch` branch into the `rack` subdirectory of your `master` branch of your main project:
1099
+
1100
+ $ git read-tree --prefix=rack/ -u rack_branch
1101
+
1102
+ When you commit, it looks like you have all the Rack files under that subdirectory — as though you copied them in from a tarball. What gets interesting is that you can fairly easily merge changes from one of the branches to the other. So, if the Rack project updates, you can pull in upstream changes by switching to that branch and pulling:
1103
+
1104
+ $ git checkout rack_branch
1105
+ $ git pull
1106
+
1107
+ Then, you can merge those changes back into your master branch. You can use `git merge -s subtree` and it will work fine; but Git will also merge the histories together, which you probably don’t want. To pull in the changes and prepopulate the commit message, use the `--squash` and `--no-commit` options as well as the `-s subtree` strategy option:
1108
+
1109
+ $ git checkout master
1110
+ $ git merge --squash -s subtree --no-commit rack_branch
1111
+ Squash commit -- not updating HEAD
1112
+ Automatic merge went well; stopped before committing as requested
1113
+
1114
+ All the changes from your Rack project are merged in and ready to be committed locally. You can also do the opposite — make changes in the `rack` subdirectory of your master branch and then merge them into your `rack_branch` branch later to submit them to the maintainers or push them upstream.
1115
+
1116
+ To get a diff between what you have in your `rack` subdirectory and the code in your `rack_branch` branch — to see if you need to merge them — you can’t use the normal `diff` command. Instead, you must run `git diff-tree` with the branch you want to compare to:
1117
+
1118
+ $ git diff-tree -p rack_branch
1119
+
1120
+ Or, to compare what is in your `rack` subdirectory with what the `master` branch on the server was the last time you fetched, you can run
1121
+
1122
+ $ git diff-tree -p rack_remote/master
1123
+
1124
+ ## Summary ##
1125
+
1126
+ You’ve seen a number of advanced tools that allow you to manipulate your commits and staging area more precisely. When you notice issues, you should be able to easily figure out what commit introduced them, when, and by whom. If you want to use subprojects in your project, you’ve learned a few ways to accommodate those needs. At this point, you should be able to do most of the things in Git that you’ll need on the command line day to day and feel comfortable doing so.