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,897 @@
1
+ # Распределённый Git #
2
+
3
+ Теперь, когда вы обзавелись настроенным удалённым Git-репозиторием, являющимся местом, где разработчики могут обмениваться своим кодом, а также познакомились с основными командами Git'а для локальной работы, мы рассмотрим, как задействовать некоторые распределённые рабочие процессы, предлагаемые Git'ом.
4
+
5
+ В этой главе мы рассмотрим работу с Git'ом в распределённой среде как в роли рядового разработчика, так и в роли системного интегратора. То есть вы научитесь успешно вносить свой код в проект, делая это как можно более просто и для вас, и для владельца проекта, а также научитесь тому, как сопровождать проекты, в работе над которыми участвует множество человек.
6
+
7
+ ## Распределённые рабочие процессы ##
8
+
9
+ В отличие от централизованных систем контроля версий, распределённая природа Git'а позволяет вам быть гораздо более гибким в отношении участия разработчиков в работе над проектами. В централизованных системах все разработчики являются узлами сети, более или менее одинаково работающими на центральном хабе. Однако, в Git'е каждый разработчик потенциально является и узлом, и хабом. То есть каждый разработчик может как вносить код в другие репозитории, так и содержать публичный репозиторий, на основе которого работают другие разработчики, и в который они вносят свои изменения. Это даёт вашей команде возможность использовать любой из множества различных способов осуществления рабочего процесса в ваших проектах, поэтому мы рассмотрим несколько распространённых подходов, пользующихся гибкостью Git'а. Мы рассмотрим сильные стороны и возможные недостатки каждого подхода; вы можете выбрать для себя один из них, а можете совместить особенности сразу нескольких подходов.
10
+
11
+ ### Централизованный рабочий процесс ###
12
+
13
+ В централизованных системах существует, как правило, одна модель совместной разработки — централизованный рабочий процесс. Один центральный хаб, или репозиторий, может принимать код, а все остальные синхронизируют свою работу с ним. Некоторое число разработчиков являются узлами — клиентами этого хаба — и синхронизируются с ним одним (см. рис. 5-1).
14
+
15
+ Insert 18333fig0501.png
16
+ Рисунок 5-1. Централизованный рабочий процесс.
17
+
18
+ Это значит, что если два разработчика выполняют клонирование с хаба и оба делают изменения в проекте, то первый из них, кто отправит свои изменения обратно на хаб, сделает это без проблем. Второй разработчик должен взять наработки первого и выполнить слияние перед тем, как отправить свои изменения, так чтобы не перезаписать изменения первого разработчика. Этот принцип справедлив для Git'а точно так же, как и для Subversion (или любой другой ЦСКВ), и в Git'е такая модель работает отлично.
19
+
20
+ Если у вас небольшая команда или вас полностью устраивает рабочий процесс централизованного типа, применяемый в вашей компании, вы можете просто продолжить использовать такой рабочий процесс и в Git'е. Просто настройте один репозиторий и дайте каждому в вашей команде права на отправку изменений; Git не позволит пользователям перезаписывать наработки друг друга. Если какой-то разработчик склонирует репозиторий, сделает в нём изменения, а затем попытается выложить эти изменения, в то время как другой разработчик уже успел отправить свои, сервер отклонит изменения этого разработчика. Ему будет сказано, что он пытается выложить изменения, для которых невозможно выполнить перемотку (fast-forward), и что надо сначала извлечь данные с сервера, выполнить слияние, а уже потом отправлять свои изменения. Такой рабочий процесс привлекателен для большого количества людей, так как это та модель, с которой многие знакомы и которая многим понятна.
21
+
22
+ ### Рабочий процесс с менеджером по интеграции ###
23
+
24
+ Так как Git позволяет иметь несколько удалённых репозиториев, существует возможность ведения такого рабочего процесса, при котором каждый разработчик имеет права на запись в свой собственный публичный репозиторий и права на чтение для всех остальных. Этот сценарий часто подразумевает существование канонического репозитория, который представляет собой "официальный" проект. Чтобы принять участие в работе над этим проектом, надо создать свою собственную публичную копию проекта и выложить туда свои изменения. Потом вы можете отправить запрос владельцу основного проекта на внесение в него ваших изменений. Он может добавить ваш репозиторий в качестве удалённого, протестировать локально ваши изменения, слить их со своей веткой и затем отправить обратно в публичный репозиторий. Этот процесс осуществляется следующим образом (см. рис. 5-2):
25
+
26
+ 1. Владелец проекта выкладывает файлы в публичный репозиторий.
27
+ 2. Участники проекта клонируют этот репозиторий и делают изменения.
28
+ 3. Участники выкладывают изменения в свои собственные публичные репозитории.
29
+ 4. Участник проекта отправляет владельцу письмо с просьбой включения его изменений.
30
+ 5. Владелец проекта добавляет репозиторий участника как удалённый и локально выполняет слияние.
31
+ 6. Владелец отправляет слитые изменения в основной репозиторий.
32
+
33
+ Insert 18333fig0502.png
34
+ Рисунок 5-2. Рабочий процесс с менеджером по интеграции.
35
+
36
+ Это очень распространённый тип рабочего процесса для сайтов вроде GitHub, где можно легко форкнуть проект и выложить свои изменения на всеобщее обозрение в собственную копию. Одно из главных преимуществ такого подхода — возможность продолжать работать, в то время как владелец основного репозитория может включить себе ваши изменения, когда ему угодно. Участникам проекта не придётся ждать включения своих изменений в проект — каждый может работать в своём собственном ритме.
37
+
38
+ ### Рабочий процесс с диктатором и его помощниками ###
39
+
40
+ Это одна из разновидностей рабочего процесса с множеством репозиториев. В основном он используется в огромных проектах с сотнями участников; ядро Linux — яркий тому пример. Несколько менеджеров по интеграции заведуют разными частями репозитория; этих людей называют помощниками. У всех этих помощников есть только один менеджер по интеграции, которого называют благосклонным диктатором. Репозиторий благосклонного диктатора служит эталонным репозиторием, откуда все участники проекта должны брать изменения. Этот процесс происходит так (см. рис. 5-3):
41
+
42
+ 1. Обычные разработчики работают над своими тематическими ветками и перемещают свою работу на вершину ветки master. Ветка master — это та ветка, которая находится у диктатора.
43
+ 2. Помощники сливают тематические ветки разработчиков в свои ветки master.
44
+ 3. Диктатор выполняет слияние веток master своих помощников со своей веткой master.
45
+ 4. Диктатор отправляет свою ветку master в эталонный репозиторий, чтобы остальные разработчики могли выполнять перемещение на неё.
46
+
47
+ Insert 18333fig0503.png
48
+ Рисунок 5-3. Рабочий процесс с благосклонным диктатором.
49
+
50
+ Этот тип рабочего процесса не является распространённым, но он может быть полезен в очень больших проектах или в сильно иерархическом окружении, так как он позволяет лидеру проекта (диктатору) передать другим полномочия по выполнению большой части работ и собирать код большими порциями с нескольких мест перед его интеграцией.
51
+
52
+ Мы рассмотрели несколько широко используемых типов рабочих процессов, доступных при работе с распределёнными системами вроде Git'а, но, как видите, возможны различные вариации для подгонки под ваш конкретный тип рабочего процесса. Теперь, когда вы в состоянии определить, какая комбинация рабочих процессов сработает для вас лучше, мы рассмотрим несколько более специфичных примеров действий, выполняемых основными ролями участников различных процессов.
53
+
54
+ ## Содействие проекту ##
55
+
56
+ Мы узнали, что представляют собой различные рабочие процессы, также у вас должно быть достаточно хорошее понимание основ использования Git'а. В этом разделе вы узнаете о нескольких типичных способах внести свой вклад в проект.
57
+
58
+ Главная трудность в описании этого процесса состоит в том, что существует огромное количество вариаций того, как он организован. Так как Git очень гибок, люди могут осуществлять совместную работу по-разному, и проблематично описать то, как вы должны содействовать проекту — все проекты немного разные. Многое зависит от количества активных участников, от выбранного типа рабочего процесса, от ваших прав доступа к репозиториям, и, возможно, от метода принятия изменений от внешних разработчиков.
59
+
60
+ Первый фактор — это количество активных участников. Как много пользователей активно вносят свой вклад в проект и как часто? Во многих случаях это два-три разработчика с несколькими коммитами в день, возможно, меньше, для вялотекущих проектов. В по-настоящему больших компаниях или проектах число разработчиков может измеряться тысячами, с десятками или даже сотнями ежедневно поступающих патчей. Это важно, поскольку с увеличением числа разработчиков вам становится труднее убедиться, что ваши изменения можно будет чисто применить или беспрепятственно слить. Изменения, которые вы отправляете, могут оказаться устаревшими или частично сломанными той работой, которая была влита, пока вы работали, или пока ваши изменения ожидали утверждения или применения. Как сохранить свой код согласованным, а патчи применимыми?
61
+
62
+ Следующий фактор — это рабочий процесс, используемый в проекте. Он централизован, и каждый разработчик имеет равные права на запись в главный репозиторий? Есть у проекта мейнтейнер или менеджер по интеграции, который проверяет патчи? Все ли патчи проверяются и утверждаются экспертами? Вы вовлечены в этот процесс? Присутствует ли система помощников и должны ли вы сначала отправлять свою работу им?
63
+
64
+ Следующий пункт — это доступ на отправку изменений. Рабочий процесс, требуемый для внесения вклада в проект, сильно отличается в зависимости от того, имеете ли вы доступ на запись или нет. Если у вас нет доступа на запись, то как в проекте принято принимать вклад в работу? Вообще, существует ли какая-либо политика? Какой объём работы вы вносите за раз? Как часто вы это делаете?
65
+
66
+ Все эти вопросы могут повлиять на то, как эффективно вы будете вносить вклад в проект и какой рабочий процесс предпочтителен или доступен вам. Я расскажу об аспектах каждого из них на серии примеров, продвигаясь от простых к более сложным; на основе этих примеров вы сможете создать специфический нужный вам в вашей работе тип рабочего процесса.
67
+
68
+ ### Рекомендации по созданию коммитов ###
69
+
70
+ Прежде чем мы приступим к рассмотрению специфичных примеров использования, сделаем короткое замечание о сообщениях коммитов. Обладание хорошим руководством по созданию коммитов и следование ему значительно облегчает работу с Git'ом и сотрудничество с другими разработчиками. У проекта Git имеется документ с хорошими советами по созданию коммитов, из которых делаются патчи — прочитать его можно в исходном коде Git'а в файле `Documentation/SubmittingPatches`.
71
+
72
+ Во-первых, не стоит отсылать ничего с ошибками в пробельных символах. Git предоставляет простой способ их обнаружения — перед коммитом, запустите `git diff --check`, это определит возможные проблемы и перечислит их вам. Вот пример, в котором я заменил красный цвет терминала символами `X`:
73
+
74
+ $ git diff --check
75
+ lib/simplegit.rb:5: trailing whitespace.
76
+ + @git_dir = File.expand_path(git_dir)XX
77
+ lib/simplegit.rb:7: trailing whitespace.
78
+ + XXXXXXXXXXX
79
+ lib/simplegit.rb:26: trailing whitespace.
80
+ + def command(git_cmd)XXXX
81
+
82
+ Если выполните эту команду перед коммитом, то сможете понять, собираетесь ли вы сделать коммит с раздражающими разработчиков ошибками в пробельных символах.
83
+
84
+ Далее, старайтесь делать так, чтобы каждый коммит был логически отдельным набором изменений. Если можете, старайтесь делать ваши изменения обозримыми — не стоит писать код все выходные, работая над пятью задачами, а затем отправлять их все в понедельник одним массивным коммитом. Даже если вы не делали коммитов в течение выходных, воспользуйтесь индексом, чтобы разбить свою работу на части, как минимум по одному коммиту для каждой проблемы с полезным сообщением к каждому. Если некоторые из изменений затрагивают один и тот же файл, попробуйте использовать `git add --patch` для индексирования файла по частям (это подробно рассмотрено в главе 6). Снимок состояния проекта на верхушке ветки будет идентичным, сделаете ли вы один коммит или пять, покуда все ваши изменения добавлены в какой-то момент, так что попытайтесь облегчить жизнь вашим коллегам разработчикам, когда они будут просматривать ваши изменения. При таком подходе будет проще выделить или отменить одно из изменений, если возникнет такая необходимость. В главе 6 описано множество полезных ухищрений для переписывания истории и интерактивного индексирования файлов — пользуйтесь этими инструментами для изготовления ясной и понятной истории.
85
+
86
+ Последняя вещь, которую стоит иметь в виду, — это сообщение коммита. Написание качественных сообщений коммитов должно войти в привычку, это сделает сотрудничество с использованием Git'а гораздо проще. По общему правилу, ваши сообщения должны начинаться с одной строки не длиннее 50 символов, лаконично описывающей набор изменений, затем пустая строка, затем более детальное описание. Проект Git требует, чтобы детальное объяснение включало в себя мотивацию на изменения и противопоставляло вашу реализацию с предыдущим поведением — это хорошее руководство к действию. Если вы пишете сообщения к коммитам на английском языке, то хорошей идеей является использование повелительного наклонения глаголов в настоящем времени. Другими словами, пишите команды. Вместо "I added tests for" или "Adding tests for" используйте "Add tests for".
87
+
88
+ Вот шаблон, изначально написанный Тимом Поупом на сайте tpope.net:
89
+
90
+ Краткое (до 50 символов) описание изменений
91
+
92
+ Более детальное объяснение, если необходимо. Перенос на 72 символе
93
+ или около того. В некоторых контекстах первая строка рассматривается
94
+ как тема письма, а остальное как тело. Пустая строка, отделяющая сводку
95
+ от тела, важна (если вы не опустили тело целиком); если вы оставите их
96
+ вместе, инструменты, такие как rebase, могут воспринять это неправильно.
97
+
98
+ Дальнейшие параграфы идут после пустых строк
99
+
100
+ - также можно применять маркеры списков
101
+
102
+ - обычно в качестве маркера списка используется дефис или звёздочка
103
+ с одним пробелом перед ним и пустыми строками между пунктами,
104
+ хотя соглашения в этом аспекте могут разниться
105
+
106
+ Если все ваши сообщения о коммитах будут выглядеть как это, всё будет намного проще для вас и для разработчиков, с которыми вы работаете. Проект Git содержит хорошо отформатированные сообщения о коммитах — я советую вам запустить `git log --no-merges` там, чтобы увидеть, как выглядит хорошо отформатированная история коммитов проекта.
107
+
108
+ В последующих примерах и почти везде в этой книге для краткости я не форматирую сообщения так красиво, как это; вместо этого я использую опцию `-m` для команды `git commit`. Делайте, как я говорю, а не как я делаю.
109
+
110
+ ### Отдельная маленькая команда ###
111
+
112
+ Наиболее простой тип организации, с которой вы легко можете столкнуться — частный проект с одним или двумя другими разработчиками. Под термином частный я подразумеваю закрытый код, недоступный для чтения остальному миру. Вы и все остальные разработчики имеете право записи в репозиторий.
113
+
114
+ В этой среде вы можете придерживаться рабочего процесса, похожего на тот, который вы бы использовали в Subversion или другой централизованной системе. Вы по-прежнему получите такие преимущества, как локальные коммиты (коммиты в offline) и возможность гораздо более простого ветвления и слияния, но сам рабочий процесс может оставаться очень похожим; главное отличие — во время выполнения коммита слияние происходит на стороне клиента, а не на сервере.
115
+ Давайте посмотрим, как выглядел бы процесс, когда два разработчика начинают работать вместе с общим репозиторием. Первый разработчик, Джон, клонирует репозиторий, делает изменения и создаёт локальный коммит. (Я заменяю служебные сообщения знаком `...` в этих примерах, чтобы немного их сократить.)
116
+
117
+ # Машина Джона
118
+ $ git clone john@githost:simplegit.git
119
+ Initialized empty Git repository in /home/john/simplegit/.git/
120
+ ...
121
+ $ cd simplegit/
122
+ $ vim lib/simplegit.rb
123
+ $ git commit -am 'removed invalid default value'
124
+ [master 738ee87] removed invalid default value
125
+ 1 files changed, 1 insertions(+), 1 deletions(-)
126
+
127
+ Второй разработчик, Джессика, выполняет то же самое — клонирует репозиторий и делает коммит с изменениями:
128
+
129
+ # Машина Джессики
130
+ $ git clone jessica@githost:simplegit.git
131
+ Initialized empty Git repository in /home/jessica/simplegit/.git/
132
+ ...
133
+ $ cd simplegit/
134
+ $ vim TODO
135
+ $ git commit -am 'add reset task'
136
+ [master fbff5bc] add reset task
137
+ 1 files changed, 1 insertions(+), 0 deletions(-)
138
+
139
+ Теперь Джессика отправляет свою работу на сервер:
140
+
141
+ # Машина Джессики
142
+ $ git push origin master
143
+ ...
144
+ To jessica@githost:simplegit.git
145
+ 1edee6b..fbff5bc master -> master
146
+
147
+ Джон также пытается выложить свои изменения:
148
+
149
+ # Машина Джона
150
+ $ git push origin master
151
+ To john@githost:simplegit.git
152
+ ! [rejected] master -> master (non-fast forward)
153
+ error: failed to push some refs to 'john@githost:simplegit.git'
154
+
155
+ Джон не может выполнить отправку изменений, так как за это время Джессика уже отправила свои. Это очень важно понять, особенно если вы привыкли к Subversion, так как мы видим, что эти два разработчика не редактировали один и тот же файл. Хотя Subversion и выполняет автоматическое слияние на сервере, если редактировались разные файлы, при использовании Git'а вы должны слить коммиты локально. Прежде чем Джон сможет отправить свои изменения на сервер, он должен извлечь наработки Джессики и выполнить слияние:
156
+
157
+ $ git fetch origin
158
+ ...
159
+ From john@githost:simplegit
160
+ + 049d078...fbff5bc master -> origin/master
161
+
162
+ На этот момент, локальный репозиторий Джона выглядит так, как показано на рисунке 5-4.
163
+
164
+ Insert 18333fig0504.png
165
+ Рисунок 5-4. Исходный репозиторий Джона.
166
+
167
+ У Джона есть ссылка на изменения, выложенные Джессикой, и он должен слить их со своей работой перед тем, как ему разрешат её отправить:
168
+
169
+ $ git merge origin/master
170
+ Merge made by recursive.
171
+ TODO | 1 +
172
+ 1 files changed, 1 insertions(+), 0 deletions(-)
173
+
174
+ Слияние прошло без проблем — история коммитов Джона теперь выглядит как на рисунке 5-5.
175
+
176
+ Insert 18333fig0505.png
177
+ Рисунок 5-5. Репозиторий Джона после слияния с origin/master.
178
+
179
+ Теперь Джон может протестировать свой код, дабы удостовериться, что он по-прежнему работает нормально, а затем выложить свою работу, уже объединённую с работой Джессики, на сервер:
180
+
181
+ $ git push origin master
182
+ ...
183
+ To john@githost:simplegit.git
184
+ fbff5bc..72bbc59 master -> master
185
+
186
+ В результате история коммитов Джона выглядит, как показано на рисунке 5-6.
187
+
188
+ Insert 18333fig0506.png
189
+ Рисунок 5-6. История коммитов Джона после отправки изменений на сервер.
190
+
191
+ Тем временем, Джессика работала над тематической веткой. Она создала тематическую ветку с названием `issue54` и сделала три коммита в этой ветке. Она ещё не извлекала изменения Джона, так что её история коммитов выглядит, как показано на рисунке 5-7.
192
+
193
+ Insert 18333fig0507.png
194
+ Рисунок 5-7. Исходная история коммитов Джессики.
195
+
196
+ Джессика хочет синхронизировать свою работу с Джоном, так что она извлекает изменения с сервера:
197
+
198
+ # Машина Джессики
199
+ $ git fetch origin
200
+ ...
201
+ From jessica@githost:simplegit
202
+ fbff5bc..72bbc59 master -> origin/master
203
+
204
+ Эта команда извлекает наработки Джона, которые он успел выложить. История коммитов Джессики теперь выглядит как на рисунке 5-8.
205
+
206
+ Insert 18333fig0508.png
207
+ Рисунок 5-8. История коммитов Джессики после извлечения изменений Джона.
208
+
209
+ Джессика полагает, что её тематическая ветка закончена, но она хочет узнать, с чем ей нужно слить свою работу, чтобы она могла выложить её на сервер. Она запускает `git log`, чтобы выяснить это:
210
+
211
+ $ git log --no-merges origin/master ^issue54
212
+ commit 738ee872852dfaa9d6634e0dea7a324040193016
213
+ Author: John Smith <jsmith@example.com>
214
+ Date: Fri May 29 16:01:27 2009 -0700
215
+
216
+ removed invalid default value
217
+
218
+ Теперь Джессика может слить свою тематическую ветку в ветку `master`, слить работу Джона (`origin/master`) в свою ветку `master` и затем отправить изменения на сервер. Сначала она переключается на свою основную ветку, чтобы объединить всю эту работу:
219
+
220
+ $ git checkout master
221
+ Switched to branch "master"
222
+ Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
223
+
224
+ Она может слить сначала ветку `origin/master`, а может и `issue54` — обе они находятся выше в истории коммитов, так что не важно какой порядок слияния она выберет. Конечное состояние репозитория должно получиться идентичным независимо от того, какой порядок слияния она выберет; только история коммитов будет немного разная. Она решает слить ветку `issue54` первой:
225
+
226
+ $ git merge issue54
227
+ Updating fbff5bc..4af4298
228
+ Fast forward
229
+ README | 1 +
230
+ lib/simplegit.rb | 6 +++++-
231
+ 2 files changed, 6 insertions(+), 1 deletions(-)
232
+
233
+ Никаких проблем не возникло; как видите, это была обычная перемотка. Теперь Джессика сливает работу Джона (`origin/master`):
234
+
235
+ $ git merge origin/master
236
+ Auto-merging lib/simplegit.rb
237
+ Merge made by recursive.
238
+ lib/simplegit.rb | 2 +-
239
+ 1 files changed, 1 insertions(+), 1 deletions(-)
240
+
241
+ Слияние проходит нормально, и теперь история коммитов Джессики выглядит так, как показано на рисунке 5-9.
242
+
243
+ Insert 18333fig0509.png
244
+ Рисунок 5-9. История коммитов Джессики после слияния с изменениями Джона.
245
+
246
+ Теперь указатель `origin/master` доступен из ветки `master` Джессики, так что она может спокойно выполнить `git push` (полагая, что Джон не выкладывал свои изменения за это время):
247
+
248
+ $ git push origin master
249
+ ...
250
+ To jessica@githost:simplegit.git
251
+ 72bbc59..8059c15 master -> master
252
+
253
+ Каждый разработчик несколько раз выполнял коммиты и успешно сливал свою работу с работой другого; смотри рисунок 5-10.
254
+
255
+ Insert 18333fig0510.png
256
+ Рисунок 5-10. История коммитов Джессики после отправки всех изменений обратно на сервер.
257
+
258
+ Это один из простейших рабочих процессов. Вы работаете некоторое время, преимущественно в тематической ветке, и, когда приходит время, сливаете её в свою ветку `master`. Когда вы готовы поделиться этой работой с другими, вы сливаете её в ветку `master`, извлекаете изменения с сервера и сливаете `origin/master` (если за это время произошли изменения), и, наконец, отправляете свои изменения в ветку `master` на сервер. Общая последовательность действий выглядит так, как показано на рисунке 5-11.
259
+
260
+ Insert 18333fig0511.png
261
+ Рисунок 5-11. Общая последовательность событий для простого рабочего процесса с несколькими разработчиками в Git'е.
262
+
263
+ ### Отдельная команда с менеджером ###
264
+
265
+ В этом сценарии мы рассмотрим роли участников проекта в закрытых группах большего размера. Вы научитесь работе в окружении, где маленькие группы совместно работают над задачами, а затем результаты их деятельности интегрируются отдельным субъектом.
266
+
267
+ Давайте представим, что Джон и Джессика работают вместе над одной задачей, в то время как Джессика с Джози работают над другой. В этом случае компания использует рабочий процесс с менеджером по интеграции, при котором работа частных групп объединяется только определёнными инженерами (обновление ветки `master` главного репозитория может осуществляться только этими инженерами). В этом случае вся работа выполняется в ветках отдельных команд разработчиков и впоследствии объединяется воедино менеджерами по интеграции.
268
+
269
+ Давайте проследим за рабочим процессом Джессики, которая работает над двумя задачами, сотрудничая одновременно с двумя разными разработчиками. Положим, что она уже имеет свою собственную копию репозитория. Джессика решает сначала взяться за задачу `featureA`. Для этого она создаёт новую ветку и выполняет в ней некоторую работу:
270
+
271
+ # Машина Джессики
272
+ $ git checkout -b featureA
273
+ Switched to a new branch "featureA"
274
+ $ vim lib/simplegit.rb
275
+ $ git commit -am 'add limit to log function'
276
+ [featureA 3300904] add limit to log function
277
+ 1 files changed, 1 insertions(+), 1 deletions(-)
278
+
279
+ На этом этапе ей требуется поделиться своей работой с Джоном, так что она отправляет коммиты, выполненные на ветке `featureA`, на сервер. Так как Джессика не имеет права на изменение ветки `master` на сервере — только менеджеры по интеграции могут делать это — она вынуждена отправлять свои изменения в другую ветку, чтобы обмениваться работой с Джоном:
280
+
281
+ $ git push origin featureA
282
+ ...
283
+ To jessica@githost:simplegit.git
284
+ * [new branch] featureA -> featureA
285
+
286
+ Джессика сообщает по электронной почте Джону, что она выложила некоторые наработки в ветку `featureA`, и что он может проверить их. Пока Джессика ждёт ответа от Джона, она решает начать работу над веткой `featureB` вместе с Джози. Для начала она создаёт новую ветку для этой задачи, используя в качестве основы ветку `master` на сервере:
287
+
288
+ # Машина Джессики
289
+ $ git fetch origin
290
+ $ git checkout -b featureB origin/master
291
+ Switched to a new branch "featureB"
292
+
293
+ Теперь Джессика делает пару коммитов в ветке `featureB`:
294
+
295
+ $ vim lib/simplegit.rb
296
+ $ git commit -am 'made the ls-tree function recursive'
297
+ [featureB e5b0fdc] made the ls-tree function recursive
298
+ 1 files changed, 1 insertions(+), 1 deletions(-)
299
+ $ vim lib/simplegit.rb
300
+ $ git commit -am 'add ls-files'
301
+ [featureB 8512791] add ls-files
302
+ 1 files changed, 5 insertions(+), 0 deletions(-)
303
+
304
+ Репозиторий Джессики выглядит, как показано на рисунке 5-12.
305
+
306
+ Insert 18333fig0512.png
307
+ Рисунок 5-12. Исходная история коммитов у Джессики.
308
+
309
+ Джессика уже готова отправить свою работу на сервер, но получает от Джози сообщение о том, что некоторые наработки уже были выложены на сервер в ветку `featureBee`. Поэтому Джессика должна сначала слить эти изменения со своими, прежде чем она сможет отправить свою работу на сервер. Она может извлечь изменения Джози командой `git fetch`:
310
+
311
+ $ git fetch origin
312
+ ...
313
+ From jessica@githost:simplegit
314
+ * [new branch] featureBee -> origin/featureBee
315
+
316
+ Теперь Джессика может слить эти изменения в свои наработки командой `git merge`:
317
+
318
+ $ git merge origin/featureBee
319
+ Auto-merging lib/simplegit.rb
320
+ Merge made by recursive.
321
+ lib/simplegit.rb | 4 ++++
322
+ 1 files changed, 4 insertions(+), 0 deletions(-)
323
+
324
+ Есть небольшая проблема — ей нужно выложить изменения из своей ветки `featureB` в ветку `featureBee` на сервере. Она может сделать это при помощи команды `git push`, указав название локальной и удалённой ветки, разделённые двоеточием:
325
+
326
+ $ git push origin featureB:featureBee
327
+ ...
328
+ To jessica@githost:simplegit.git
329
+ fba9af8..cd685d1 featureB -> featureBee
330
+
331
+ Это называется _refspec_. Смотри главу 9, где более детально обсуждаются спецификации ссылок и различные вещи, которые вы можете делать с ними.
332
+
333
+ Далее, Джон сообщает Джессике по почте, что он добавил некоторые изменения в ветку `featureA` и просит её проверить их. Она выполняет `git fetch`, чтобы получить внесённые Джоном изменения:
334
+
335
+ $ git fetch origin
336
+ ...
337
+ From jessica@githost:simplegit
338
+ 3300904..aad881d featureA -> origin/featureA
339
+
340
+ Затем, используя команду `git log`, она смотрит, что же было изменено:
341
+
342
+ $ git log origin/featureA ^featureA
343
+ commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
344
+ Author: John Smith <jsmith@example.com>
345
+ Date: Fri May 29 19:57:33 2009 -0700
346
+
347
+ changed log output to 30 from 25
348
+
349
+ Наконец, она сливает работу Джона в свою собственную ветку `featureA`:
350
+
351
+ $ git checkout featureA
352
+ Switched to branch "featureA"
353
+ $ git merge origin/featureA
354
+ Updating 3300904..aad881d
355
+ Fast forward
356
+ lib/simplegit.rb | 10 +++++++++-
357
+ 1 files changed, 9 insertions(+), 1 deletions(-)
358
+
359
+ Джессика хочет кое-что подправить, так что она опять делает коммит и затем отправляет изменения на сервер:
360
+
361
+ $ git commit -am 'small tweak'
362
+ [featureA 774b3ed] small tweak
363
+ 1 files changed, 1 insertions(+), 1 deletions(-)
364
+ $ git push origin featureA
365
+ ...
366
+ To jessica@githost:simplegit.git
367
+ 3300904..774b3ed featureA -> featureA
368
+
369
+ История коммитов Джессики теперь выглядит так, как показано на рисунке 5-13.
370
+
371
+ Insert 18333fig0513.png
372
+ Рисунок 5-13. История Джессики после внесения коммитов в ветку с решаемой задачей.
373
+
374
+ Джессика, Джози и Джон информируют менеджеров по интеграции, что ветки `featureA` и `featureBee` на сервере готовы к интеграции в основную ветку разработки. После того, как они интегрируют эти ветки в основную версию, извлечение данных с сервера приведёт к появлению новых коммитов слияния. Таким образом, история коммитов станет выглядеть так, как на рисунке 5-14.
375
+
376
+ Insert 18333fig0514.png
377
+ Рисунок 5-14. История коммитов Джессики после слияния двух тематических веток.
378
+
379
+ Множество групп переходят на Git именно из-за возможности параллельной работы нескольких команд с последующим объединением разных линий разработки. Огромное преимущество Git'а — возможность маленьких подгрупп большой команды работать вместе через удалённые ветки, не мешая при этом всей команде. Последовательность событий в рассмотренном здесь рабочем процессе представлена на рисунке 5-15.
380
+
381
+ Insert 18333fig0515.png
382
+ Рисунок 5-15. Основная последовательность действий для рабочего процесса в команде с менеджером по интеграции.
383
+
384
+ ### Небольшой открытый проект ###
385
+
386
+ Внести вклад в открытый проект — это немного другое. Из-за того, что у вас нет прав на прямое изменение веток проекта, требуется какой-нибудь другой путь для обмена наработками с мейнтейнерами. Первый пример описывает участие в проекте через разветвление (fork) на Git-хостингах, на которых это делается достаточно просто. Сайты repo.or.cz и GitHub оба поддерживают такую возможность, и большая часть мейнтейнеров проектов придерживаются такого способа сотрудничества. В следующем разделе рассматриваются проекты, которые предпочитают принимать патчи по e-mail.
387
+
388
+ Сначала вы скорее всего захотите склонировать основной репозиторий, создать тематическую ветку для одного или нескольких патчей, которые вы собираетесь внести в проект, и выполнить свою работу в ней. Последовательность действий выглядит следующим образом:
389
+
390
+ $ git clone (url)
391
+ $ cd project
392
+ $ git checkout -b featureA
393
+ $ (выполнение работы)
394
+ $ git commit
395
+ $ (выполнение работы)
396
+ $ git commit
397
+
398
+ Возможно, у вас возникнет желание воспользоваться `rebase -i`, чтобы сплющить (squash) свои наработки в единый коммит, или реорганизовать наработки в коммитах таким образом, чтобы их было проще воспринимать мейнтейнерам проекта — об интерактивном перемещении будет рассказано в главе 6.
399
+
400
+ Если вы закончили работу со своей веткой и готовы поделиться наработками с мейнтейнерами, перейдите на страницу исходного проекта и нажмите кнопку "Fork", создав таким образом свою собственную копию проекта, доступную на запись. Затем вам нужно добавить URL этого нового репозитория в список удалённых репозиториев, в нашем случае мы назовём его `myfork`:
401
+
402
+ $ git remote add myfork (url)
403
+
404
+ Вам нужно отправить свои наработки в этот репозиторий. Проще всего будет отправить в удалённый репозиторий ту ветку, над которой вы работаете, а не сливать её в ветку `master` и отправлять потом её. Это объясняется следующим образом — если ваша работа не будет принята или будет принята только частично, вам не придётся откатывать назад свою ветку `master`. Если мейнтейнеры сольют, переместят или частично включат вашу работу, вы, в конечном счёте, получите её обратно при получении изменений из их репозитория:
405
+
406
+ $ git push myfork featureA
407
+
408
+ Когда ваши наработки будут отправлены в ваш форк, вам нужно будет послать уведомление мейнтейнеру. Его часто называют запросом на включение (pull request), вы можете либо сгенерировать его через сайт — на GitHub'е есть кнопка "pull request", автоматически уведомляющая мейнтейнера, либо выполнить команду `git request-pull` и вручную отправить её вывод по почте мейнтейнеру.
409
+
410
+ Команда `request-pull` принимает в качестве аргумента имя базовой ветки, в которую вы хотите включить свою работу, и URL репозитория, из которого мейнтейнер может получить ваши наработки. Команда выводит короткую сводку всех изменений, которые вы просите включить в проект. Например, если Джессика хочет послать Джону запрос на включение, когда она сделала пару коммитов в тематической ветке и уже отправила её на сервер, ей следует выполнить следующее:
411
+
412
+ $ git request-pull origin/master myfork
413
+ The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
414
+ John Smith (1):
415
+ added a new function
416
+
417
+ are available in the git repository at:
418
+
419
+ git://githost/simplegit.git featureA
420
+
421
+ Jessica Smith (2):
422
+ add limit to log function
423
+ change log output to 30 from 25
424
+
425
+ lib/simplegit.rb | 10 +++++++++-
426
+ 1 files changed, 9 insertions(+), 1 deletions(-)
427
+
428
+ Вывод может быть отправлен мейнтейнеру — он содержит список коммитов, информацию о том, где начинается ветка с изменениями, и указывает, откуда можно забрать эти изменения.
429
+
430
+ Для проекта, мейнтейнером которого вы не являетесь, проще иметь ветку `master`, которая отслеживает ветку `origin/master`, и выполнять работу в тематических ветках, которые вы легко сможете удалить, в случае если они будут отклонены. Если вы распределяете свои наработки по различным темам в тематических ветках, вам будет проще выполнить перемещение своей работы, в случае если верхушка главного репозитория переместится за время работы и ваши коммиты уже не получится применить без конфликтов. Например, если вы планируете отправить в проект работу по другой теме, не продолжайте работать внутри тематической ветки, которую вы только что отправили, начните снова с ветки `master` главного репозитория:
431
+
432
+ $ git checkout -b featureB origin/master
433
+ $ (выполнение работы)
434
+ $ git commit
435
+ $ git push myfork featureB
436
+ $ (отправка письма мейнтейнеру)
437
+ $ git fetch origin
438
+
439
+ Теперь каждая из ваших тем представляет собой нечто похожее на очередь из патчей, которую вы можете перезаписывать, перемещать, модифицировать, не оказывая влияния на остальные, как на рисунке 5-16.
440
+
441
+ Insert 18333fig0516.png
442
+ Рисунок 5-16. Исходная история коммитов при работе над featureB.
443
+
444
+ Давайте представим, что мейнтейнер проекта включил в основную версию чью-то группу патчей. Затем он попытался включить вашу первую ветку, но слияние уже не проходит гладко. В этом случае вы можете попробовать переместить эту ветку на верхушку ветки `origin/master`, разрешить конфликты для мейнтейнера и затем заново представить свои изменения на рассмотрение:
445
+
446
+ $ git checkout featureA
447
+ $ git rebase origin/master
448
+ $ git push -f myfork featureA
449
+
450
+ Так вы перепишете свою историю коммитов, чтобы она выглядела так, как на рисунке 5-17.
451
+
452
+ Insert 18333fig0517.png
453
+ Рисунок 5-17. История коммитов после работы в featureA.
454
+
455
+ Так как вы переместили ветку, команде push вы должны передать опцию `-f`, чтобы иметь возможность заменить ветку `featureA` на сервере. Есть альтернатива — выложить новую работу на сервер в другую ветку (возможно, назвав её `featureAv2`).
456
+
457
+ Давайте рассмотрим более вероятный сценарий: мейнтейнер просмотрел вашу работу во второй ветке, и ему понравилась ваша идея, но он хотел бы, чтобы вы изменили некоторые детали реализации. Воспользуемся этой возможностью, чтобы заодно переместить вашу работу так, чтобы она базировалась на текущей версии ветки `master` в проекте. Создадим новую ветку, базирующуюся на текущей ветке `origin/master`, уплотним (squash) здесь изменения из ветки `featureB`, разрешим все конфликты, которые могут возникнуть, сделаем необходимые изменения в реализации вашей идеи и затем выложим всё это в виде новой ветки:
458
+
459
+ $ git checkout -b featureBv2 origin/master
460
+ $ git merge --no-commit --squash featureB
461
+ $ (изменение реализации)
462
+ $ git commit
463
+ $ git push myfork featureBv2
464
+
465
+ Опция `--squash` берёт всю работу на сливаемой ветке (featureB) и сжимает её в один коммит, не являющийся коммитом-слиянием, и помещает его на верхушку текущей ветки. Опция `--no-commit` сообщает Git'у, что не нужно автоматически записывать коммит. Это позволит вам внести все изменения с другой ветки и затем сделать ещё ряд изменений перед записью нового коммита.
466
+
467
+ Теперь вы можете отправить мейнтейнеру сообщение о том, что вы сделали требуемые изменения, и они могут быть найдены в вашей ветке `featureBv2` (см. рис. 5-18).
468
+
469
+ Insert 18333fig0518.png
470
+ Рисунок 5-18. История коммитов после работы над featureBv2.
471
+
472
+ ### Большой открытый проект ###
473
+
474
+ Во многих крупных проектах есть установленные процедуры принятия патчей — вам потребуется выяснить точные правила для каждого проекта отдельно, так как они везде разные. Однако, многие крупные открытые проекты принимают патчи через списки рассылки для разработчиков, так что мы сейчас рассмотрим пример использования этого способа.
475
+
476
+ Рабочий процесс похож на описанный ранее — вы создаёте тематическую ветку для каждой серии патчей, над которой работаете. Отличие состоит в процессе внесения этих изменений в проект. Вместо того, чтобы создавать ответвление (fork) от проекта и отправлять наработки в свой собственный репозиторий с правами на запись, вы генерируете e-mail версию каждой серии коммитов и отправляете её в список рассылки для разработчиков:
477
+
478
+ $ git checkout -b topicA
479
+ $ (выполнение работы)
480
+ $ git commit
481
+ $ (выполнение работы)
482
+ $ git commit
483
+
484
+ Теперь у нас есть два коммита, которые нужно отправить в список рассылки. Воспользуемся командой `git format-patch`, чтобы сгенерировать файлы в формате mbox, которые вы сможете отправить по почте. Эта команда превращает каждый коммит в электронное письмо, темой которого является первая строка сообщения коммита, а оставшаяся часть сообщения коммита и патч, который он представляет, являются телом письма. Хорошей особенностью этого является то, что применение патча из сгенерированного командой `format-patch` электронного письма сохраняет всю информацию о коммите. Мы увидим это в следующем разделе, когда будем применять такие патчи:
485
+
486
+ $ git format-patch -M origin/master
487
+ 0001-add-limit-to-log-function.patch
488
+ 0002-changed-log-output-to-30-from-25.patch
489
+
490
+ Команда `format-patch` создаёт файлы с патчами и выводит их названия. Опция `-M` сообщает Git'у о необходимости отслеживания переименований файлов. Итоговые патчи выглядят так:
491
+
492
+ $ cat 0001-add-limit-to-log-function.patch
493
+ From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
494
+ From: Jessica Smith <jessica@example.com>
495
+ Date: Sun, 6 Apr 2008 10:17:23 -0700
496
+ Subject: [PATCH 1/2] add limit to log function
497
+
498
+ Limit log functionality to the first 20
499
+
500
+ ---
501
+ lib/simplegit.rb | 2 +-
502
+ 1 files changed, 1 insertions(+), 1 deletions(-)
503
+
504
+ diff --git a/lib/simplegit.rb b/lib/simplegit.rb
505
+ index 76f47bc..f9815f1 100644
506
+ --- a/lib/simplegit.rb
507
+ +++ b/lib/simplegit.rb
508
+ @@ -14,7 +14,7 @@ class SimpleGit
509
+ end
510
+
511
+ def log(treeish = 'master')
512
+ - command("git log #{treeish}")
513
+ + command("git log -n 20 #{treeish}")
514
+ end
515
+
516
+ def ls_tree(treeish = 'master')
517
+ --
518
+ 1.6.2.rc1.20.g8c5b.dirty
519
+
520
+ Вы также можете отредактировать эти файлы с патчами, чтобы добавить в электронное письмо какую-то информацию, которую вы не хотите показывать в сообщении коммита. Если вы добавите текст между строкой `---` и началом патча (строка `lib/simplegit.rb`), то разработчик сможет его прочитать, а при применении патча он будет выброшен.
521
+
522
+ Чтобы отправить эти файлы в список рассылки, вы можете либо вставить файл в своём почтовом клиенте, либо отправить его через специальную программу из командной строки. Вставка текста часто приводит к ошибкам форматирования, особенно в "умных" клиентах, которые не сохраняют символы перевода строки и пробельные символы в исходном виде. К счастью, Git предоставляет инструмент, позволяющий вам передавать через IMAP правильно отформатированные патчи. Для вас применение этого инструмента может оказаться более простым. Я покажу, как отсылать патчи через Gmail, так как именно этот агент я и использую; вы можете прочесть подробные инструкции для множества почтовых программ в вышеупомянутом файле `Documentation/SubmittingPatches`, находящемся в исходном коде Git'а.
523
+
524
+ Для начала нам необходимо настроить секцию imap в файле `~/.gitconfig`. Можете добавить все значения по одному несколькими командами `git config`, или можете добавить их все сразу вручную; но в итоге ваш файл конфигурации должен выглядеть примерно так:
525
+
526
+ [imap]
527
+ folder = "[Gmail]/Drafts"
528
+ host = imaps://imap.gmail.com
529
+ user = user@gmail.com
530
+ pass = p4ssw0rd
531
+ port = 993
532
+ sslverify = false
533
+
534
+ Если ваш IMAP-сервер не использует SSL, две последние строки могут отсутствовать, а параметр host примет значение `imap://` вместо `imaps://`.
535
+ Когда закончите с настройками, воспользуйтесь командой `git send-email`, чтобы поместить свою серию патчей в папку Drafts на указанном IMAP-сервере:
536
+
537
+ $ git send-email *.patch
538
+ 0001-added-limit-to-log-function.patch
539
+ 0002-changed-log-output-to-30-from-25.patch
540
+ Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
541
+ Emails will be sent from: Jessica Smith <jessica@example.com>
542
+ Who should the emails be sent to? jessica@example.com
543
+ Message-ID to be used as In-Reply-To for the first email? y
544
+
545
+ Затем Git выдаёт кучу служебных сообщений, которые для каждого отсылаемого патча выглядят следующим образом:
546
+
547
+ (mbox) Adding cc: Jessica Smith <jessica@example.com> from
548
+ \line 'From: Jessica Smith <jessica@example.com>'
549
+ OK. Log says:
550
+ Sendmail: /usr/sbin/sendmail -i jessica@example.com
551
+ From: Jessica Smith <jessica@example.com>
552
+ To: jessica@example.com
553
+ Subject: [PATCH 1/2] added limit to log function
554
+ Date: Sat, 30 May 2009 13:29:15 -0700
555
+ Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
556
+ X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
557
+ In-Reply-To: <y>
558
+ References: <y>
559
+
560
+ Result: OK
561
+
562
+ Если всё прошло успешно, то сейчас вы можете перейти в свою папку Drafts, изменить поле 'To' на адрес списка рассылки, в который вы собираетесь послать патчи, возможно, указать адрес мейнтейнера или лица, отвечающего за нужную часть проекта, в поле 'CC' и отправить сообщение.
563
+
564
+ ### Итоги ###
565
+
566
+ В этом разделе мы рассмотрели ряд общепринятых рабочих процессов, применяемых в разных типах проектов, использующих Git, c которыми вы наверняка столкнётесь. Также были представлены несколько новых инструментов, призванных помочь вам в организации этих процессов. Далее мы рассмотрим, как осуществляется работа с противоположной стороны баррикады — как сопровождать проект, использующий Git. Вы научитесь роли благосклонного диктатора или роли менеджера по интеграции.
567
+
568
+ ## Сопровождение проекта ##
569
+
570
+ В дополнение к тому, как эффективно работать над проектом, вам, наверняка, необходимо также знать, как самому поддерживать проект. Сопровождение проекта может заключаться в принятии и применении патчей, сгенерированных с помощью 'format-patch' и отправленных вам по почте, или в интеграции изменений из веток тех репозиториев, которые вы добавили в качестве удалённых (remotes) для вашего проекта. Неважно, поддерживаете ли вы эталонный репозиторий проекта или хотите помочь с проверкой и утверждением патчей, вам необходимо выработать метод приёма наработок, который будет наиболее понятным для других участников и не будет изменяться в течение длительного срока.
571
+
572
+ ### Работа с тематическими ветками ###
573
+
574
+ Если вы решаете, интегрировать ли новые наработки, как правило, неплохо было бы опробовать их в какой-нибудь временной тематической ветке, специально созданной для их тестирования. Так будет легче подправить отдельные патчи или забросить их до лучших времён, если что-то не работает. Если вы дадите ветке простое имя, основанное на теме содержащейся в ней работы, например, `ruby_client`, или как-нибудь так же наглядно, то вы сможете легко вспомнить, для чего эта ветка, если вам вдруг придётся отложить работу с ней и вернуться к ней позднее. В проекте Git мейнтейнер, как правило, создаёт ветки с добавлением пространства имён — к примеру, 'sc/ruby_client', где 'sc' — это сокращённое имя автора, приславшего свою работу.
575
+ Как вы уже знаете, создать ветку, основанную на вашей ветке `master`, можно следующим образом:
576
+
577
+ $ git branch sc/ruby_client master
578
+
579
+ Или, если вы хотите сразу переключиться на создаваемую ветку, можно воспользоваться командой `checkout -b`:
580
+
581
+ $ git checkout -b sc/ruby_client master
582
+
583
+ Теперь вы готовы к тому, чтобы принять изменения в данную тематическую ветку и определить, хотите ли вы влить их в свои стабильные ветки или нет.
584
+
585
+ ### Применение патчей, отправленных по почте ###
586
+
587
+ Если вы получили по электронной почте патч, который вам нужно интегрировать в свой проект, вам необходимо применить патч в тематической ветке, чтобы его оценить. Есть два способа применения отправленных по почте патчей: с помощью команды `git apply` или команды `git am`.
588
+
589
+ #### Применение патчей с помощью команды apply ####
590
+
591
+ Если вы получили чей-то патч, сгенерированный с помощью команды `git diff` или Unix-команды `diff`, вы можете применить его при помощи команды `git apply`. Полагая, что вы сохранили патч в `/tmp/patch-ruby-client.patch`, вы можете применить его следующим образом:
592
+
593
+ $ git apply /tmp/patch-ruby-client.patch
594
+
595
+ Эта команда внесёт изменения в файлы в рабочем каталоге. Она практически идентична выполнению команды `patch -p1` для применения патча, хотя она более параноидальна и допускает меньше нечётких совпадений, чем `patch`. К тому же она способна справиться с добавлением, удалением и переименованием файлов, описанными в формате `git diff`, чего команда `patch` сделать не сможет. И, наконец, `git apply` реализует модель "применить всё или ничего", тогда как `patch` позволяет частично применять патч-файлы, оставляя ваш рабочий каталог в странном и непонятном состоянии. Команда `git apply` в целом гораздо более параноидальна, чем `patch`. Она не создаст для вас коммит — после выполнения команды вы должны вручную проиндексировать внесённые изменения и сделать коммит.
596
+
597
+ Кроме того, вы можете использоваться `git apply`, чтобы узнать, чисто ли накладывается патч, ещё до того, как вы будете применять его на самом деле — для этого выполните `git apply --check`, указав нужный патч:
598
+
599
+ $ git apply --check 0001-seeing-if-this-helps-the-gem.patch
600
+ error: patch failed: ticgit.gemspec:1
601
+ error: ticgit.gemspec: patch does not apply
602
+
603
+ Если никакого вывода нет, то патч должен наложиться без ошибок. Если проверка прошла неудачно, то команда завершится с ненулевым статусом, так что вы можете использовать её при написании сценариев.
604
+
605
+ #### Применение патчей с помощью команды am ####
606
+
607
+ Если разработчик является достаточно хорошим пользователем Git'а и применил команду `format-patch` для создания своего патча, то ваша задача становится проще, так как такой патч содержит информацию об авторе и сообщение коммита. По возможности поощряйте участников проекта на использование команды `format-patch` вместо `diff` при генерировании патчей для вас. Команду `git apply` стоит использовать, только если нет другого выхода, и патчи уже созданы при помощи `diff`.
608
+
609
+ Чтобы применить патч, созданный при помощи `format-patch`, используйте команду `git am`. С технической точки зрения, `git am` читает mbox-файл, который является простым текстовым форматом для хранения одного или нескольких электронных писем в одном текстовом файле. Он выглядит примерно следующим образом:
610
+
611
+ From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
612
+ From: Jessica Smith <jessica@example.com>
613
+ Date: Sun, 6 Apr 2008 10:17:23 -0700
614
+ Subject: [PATCH 1/2] add limit to log function
615
+
616
+ Limit log functionality to the first 20
617
+
618
+ Это начало вывода команды `format-patch`, который мы уже видели в предыдущем разделе. Это одновременно и правильный mbox формат для e-mail. Если кто-то прислал вам по почте патч, правильно воспользовавшись для этого командой `git send-email`, и вы сохранили это сообщение в mbox-формате, тогда вы можете указать этот mbox-файл команде `git am` — в результате команда начнёт применять все патчи, которые найдёт. Если вы пользуетесь почтовым клиентом, способным сохранять несколько электронных писем в один mbox-файл, то можете сохранить всю серию патчей в один файл и затем использовать команду `git am` для применения всех патчей сразу.
619
+
620
+ Однако, если кто-нибудь загрузил патч, созданный через `format-patch`, в тикет-систему или что-либо подобное, вы можете сохранить файл локально и затем передать его команде `git am`, чтобы его наложить:
621
+
622
+ $ git am 0001-limit-log-function.patch
623
+ Applying: add limit to log function
624
+
625
+ Как видите, патч был применён без ошибок, и за вас автоматически был создан новый коммит. Информация об авторе берётся из полей `From` и `Date` письма, а сообщение коммита извлекается из поля `Subject` и тела (до начала самого патча) электронного письма. Например, если применить патч из mbox-файла приведённого выше примера, то созданный для него коммит будет выглядеть следующим образом:
626
+
627
+ $ git log --pretty=fuller -1
628
+ commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
629
+ Author: Jessica Smith <jessica@example.com>
630
+ AuthorDate: Sun Apr 6 10:17:23 2008 -0700
631
+ Commit: Scott Chacon <schacon@gmail.com>
632
+ CommitDate: Thu Apr 9 09:19:06 2009 -0700
633
+
634
+ add limit to log function
635
+
636
+ Limit log functionality to the first 20
637
+
638
+ В поле `Commit` указан человек, применивший патч, а в `CommitDate` — время его применения. Информация `Author` определяет человека, создавшего патч изначально, и время его создания.
639
+
640
+ Однако возможна ситуация, когда патч не наложится без ошибок. Возможно, ваша основная ветка слишком далеко ушла вперёд относительно той, на которой патч был основан, или этот патч зависит от другого патча, который вы ещё не применили. В этом случае выполнение команды `git am` будет приостановлено, а у вас спросят, что вы хотите сделать:
641
+
642
+ $ git am 0001-seeing-if-this-helps-the-gem.patch
643
+ Applying: seeing if this helps the gem
644
+ error: patch failed: ticgit.gemspec:1
645
+ error: ticgit.gemspec: patch does not apply
646
+ Patch failed at 0001.
647
+ When you have resolved this problem run "git am --resolved".
648
+ If you would prefer to skip this patch, instead run "git am --skip".
649
+ To restore the original branch and stop patching run "git am --abort".
650
+
651
+ Эта команда выставляет отметки о конфликтах в каждый файл, с которым возникают проблемы, точно так же, как это происходит при операции слияния или перемещения с конфликтами. И разрешается данная ситуация тем же способом — отредактируйте файл, чтобы разрешить конфликт, добавьте новый файл в индекс, а затем выполните команду `git am --resolved`, чтобы перейти к следующему патчу:
652
+
653
+ $ (исправление файла)
654
+ $ git add ticgit.gemspec
655
+ $ git am --resolved
656
+ Applying: seeing if this helps the gem
657
+
658
+ Если вы хотите, чтобы Git постарался разрешить конфликт более умно, воспользуйтесь опцией `-3`, при использовании которой Git попытается выполнить трёхходовую операцию слияния. Эта опция не включена по умолчанию, так как она не работает в случае, если коммита, на котором был основан патч, нет в вашем репозитории. Если этот коммит всё же у вас есть — в случае когда патч был основан на публичном коммите — то опция `-3`, как правило, гораздо умнее в наложении конфликтных патчей:
659
+
660
+ $ git am -3 0001-seeing-if-this-helps-the-gem.patch
661
+ Applying: seeing if this helps the gem
662
+ error: patch failed: ticgit.gemspec:1
663
+ error: ticgit.gemspec: patch does not apply
664
+ Using index info to reconstruct a base tree...
665
+ Falling back to patching base and 3-way merge...
666
+ No changes -- Patch already applied.
667
+
668
+ В этом случае я пытался применить патч, который я уже применил. Без опции `-3` это привело бы к конфликту.
669
+
670
+ При применении серии патчей из mbox-файла, вы также можете запустить команду `am` в интерактивном режиме — в этом случае команда останавливается на каждом найденном патче и спрашивает вас, хотите ли вы его применить:
671
+
672
+ $ git am -3 -i mbox
673
+ Commit Body is:
674
+ --------------------------
675
+ seeing if this helps the gem
676
+ --------------------------
677
+ Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all
678
+
679
+ Это удобно, если у вас накопилось множество патчей, так как вы сможете сначала просмотреть патч, если вы забыли, что он из себя представляет, или отказаться применять патч, если он уже применён.
680
+
681
+ После того как вы примените все патчи по интересующей вас теме и сделаете для них коммиты в своей ветке, вы можете принять решение — интегрировать ли их в свои стабильные ветки и если да, то каким образом.
682
+
683
+ ### Проверка удалённых веток ###
684
+
685
+ Если к вам поступили наработки от человека, использующего Git и имеющего свой собственный репозиторий, в который он и отправил свои изменения, а вам он прислал ссылку на свой репозиторий и имя удалённой ветки, в которой находятся изменения, то вы можете добавить его репозиторий в качестве удалённого и выполнить слияния локально.
686
+
687
+ Например, если Джессика присылает вам письмо, в котором говорится, что у неё есть классная новая функция в ветке `ruby-client` в её репозитории, вы можете протестировать её, добавив её репозиторий в качестве удалённого для вашего проекта и выгрузив содержимое этой ветки в рабочий каталог:
688
+
689
+ $ git remote add jessica git://github.com/jessica/myproject.git
690
+ $ git fetch jessica
691
+ $ git checkout -b rubyclient jessica/ruby-client
692
+
693
+ Если она снова пришлёт вам письмо с другой веткой и с новой замечательной функцией, вы сможете сразу извлечь эти наработки и переключиться на эту ветку, так как её репозиторий уже прописан в ваших удалённых репозиториях.
694
+
695
+ Этот метод наиболее удобен, если вы работаете с человеком постоянно. Если кто-то изредка представляет вам по одному патчу, то менее затратно по времени будет принимать их по e-mail, чем заставлять всех иметь свои собственные репозитории и постоянно добавлять и удалять удалённые репозитории, чтобы получить пару патчей. Также вы, скорее всего, не захотите иметь у себя сотни удалённых репозиториев — для всех, кто предоставил вам один или два патча. Хотя сценарии и функции хостингов могут упростить эту ситуацию — всё зависит от того, как ведёте разработку вы и участники вашего проекта.
696
+
697
+ Другим преимуществом данного подхода является тот факт, что вы получаете не только патчи, но и историю коммитов. Если вы даже обнаружите проблемы со слиянием, то вы, по крайней мере, будете знать, на каком коммите в вашей истории основана их работа. Правильное трёхходовое слияние в этом случае используется по умолчанию, что лучше, чем передать `-3` и надеяться, что патч был сгенерирован на основе публичного коммита, к которому у вас есть доступ.
698
+
699
+ Если вы не работаете с человеком постоянно, но всё же хотите принять его изменения таким способом, можете указать URL его удалённого репозитория команде `git pull`. Так вы получите нужные изменения, а URL не будет сохранён в списке удалённых репозиториев:
700
+
701
+ $ git pull git://github.com/onetimeguy/project.git
702
+ From git://github.com/onetimeguy/project
703
+ * branch HEAD -> FETCH_HEAD
704
+ Merge made by recursive.
705
+
706
+ ### Определение вносимых изменений ###
707
+
708
+ Сейчас у вас есть тематическая ветка, содержащая наработки участников проекта. На этом этапе вы можете определить, что бы вы хотели с ними сделать. В этом разделе мы снова рассмотрим несколько команд, которые, как вы увидите, можно использовать для точного определения того, что вы собираетесь слить в свою основную ветку.
709
+
710
+ Часто полезно просмотреть все коммиты, которые есть в этой ветке, но нет в вашей ветке `master`. Исключить коммиты из ветки `master` можно добавив опцию `--not` перед именем ветки. Например, если участник вашего проекта прислал вам два патча, и вы создали ветку с именем `contrib` и применили эти патчи в ней, вы можете выполнить следующее:
711
+
712
+ $ git log contrib --not master
713
+ commit 5b6235bd297351589efc4d73316f0a68d484f118
714
+ Author: Scott Chacon <schacon@gmail.com>
715
+ Date: Fri Oct 24 09:53:59 2008 -0700
716
+
717
+ seeing if this helps the gem
718
+
719
+ commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
720
+ Author: Scott Chacon <schacon@gmail.com>
721
+ Date: Mon Oct 22 19:38:36 2008 -0700
722
+
723
+ updated the gemspec to hopefully work better
724
+
725
+ Чтобы увидеть какие изменения вносит каждый коммит, если помните, можно передать опцию `-p` команде `git log` — к каждому коммиту будет добавлен его diff.
726
+
727
+ Чтобы посмотреть полный diff того, что добавится при слиянии вашей тематической ветки с другой веткой, вам может понадобиться использовать странный трюк, чтобы получить нужный результат. Вы, возможно, решите выполнить такую команду:
728
+
729
+ $ git diff master
730
+
731
+ Эта команда выведет вам diff, но результат может ввести вас в заблуждение. Если ваша ветка `master` была промотана вперёд с того момента, когда вы создали на её основе тематическую ветку, вы, наверняка, увидите странный результат. Это происходит по той причине, что Git напрямую сравнивает снимок состояния последнего коммита тематической ветки, на которой вы находитесь, и снимок последнего коммита ветки `master`. Например, если вы добавили строку в файл в ветке `master`, прямое сравнение снимков покажет, что изменения в тематической ветке собираются эту строку удалить.
732
+
733
+ Если `master` является прямым предком вашей тематической ветки, то проблем нет. Но если две линии истории разошлись, то diff будет выглядеть так, будто вы добавляете всё новое из вашей тематической ветки и удаляете всё уникальное в ветке `master`.
734
+
735
+ То, что вы действительно хотели бы видеть — это изменения, добавленные в тематической ветке, то есть те наработки, которые вы внесёте при слиянии этой ветки с веткой `master`. Это выполняется путём сравнения последнего коммита в вашей тематической ветке с первым общим с веткой `master` предком.
736
+
737
+ Технически, вы можете сделать это, выделив общего предка явным образом и выполнив затем команду `diff`:
738
+
739
+ $ git merge-base contrib master
740
+ 36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
741
+ $ git diff 36c7db
742
+
743
+ Однако это не очень удобно, так что в Git'е есть отдельное сокращённое обозначение для выполнения того же самого — запись с тремя точками. В контексте команды `diff`, вы можете поставить три точки после названия одной из веток, чтобы увидеть дельту между последним коммитом ветки, на которой вы находитесь, и их общим предком с другой веткой:
744
+
745
+ $ git diff master...contrib
746
+
747
+ Эта команда покажет вам только те наработки в вашей текущей тематической ветке, которые были внесены после её ответвления от ветки `master`. Это очень удобный синтаксис, и его надо запомнить.
748
+
749
+ ### Интегрирование чужих наработок ###
750
+
751
+ Когда все наработки в вашей тематической ветке готовы к интегрированию в более стабильную ветку, встаёт вопрос — как это сделать? Более того — какой рабочий процесс в целом вы хотите использовать, занимаясь поддержкой своего проекта? Есть множество вариантов, так что рассмотрим некоторые из них.
752
+
753
+ #### Процессы слияния ####
754
+
755
+ Один из простых рабочих процессов заключается в слиянии наработок в ветку `master`. В этом случае ваша ветка `master` содержит основную стабильную версию кода. Если у вас в тематической ветке находится работа, которую вы уже доделали, или полученные от кого-то наработки, которые вы уже проверили, вы сливаете её в свою ветку `master`, удаляете тематическую ветку, а затем продолжаете работу. Если в вашем репозитории наработки находятся в двух ветках, названия которых `ruby_client` и `php_client` (см. рис. 5-19), и вы выполняете слияние сначала для ветки `ruby_client`, в потом для `php_client`, то ваша история коммитов в итоге будет выглядеть, как показано на рисунке 5-20.
756
+
757
+ Insert 18333fig0519.png
758
+ Рисунок 5-19. История коммитов с несколькими тематическими ветками.
759
+
760
+ Insert 18333fig0520.png
761
+ Рисунок 5-20. История коммитов после слияния тематических веток.
762
+
763
+ Это, по всей видимости, наиболее простой рабочий процесс, но при работе с большими проектами здесь возникает ряд проблем.
764
+
765
+ Если ваш проект более крупный, или вы работаете с большим количеством разработчиков, вы, вероятно, будете применять по крайней мере двухэтапный цикл слияний. При этом сценарии у вас есть две долгоживущие ветки, `master` и `develop`, и вы решили, что ветка `master` обновляется только тогда, когда выходит очень стабильный релиз, а весь новый код включается в ветку `develop`. Изменения в обеих этих ветках регулярно отправляются в публичный репозиторий. Каждый раз, когда у вас появляется новая тематическая ветка для слияния (рисунок 5-21), вы сначала сливаете её в `develop` (рисунок 5-22); затем, когда вы выпускаете релиз, вы делаете перемотку (fast-forward) ветки `master` на нужный стабильный коммит ветки `develop` (рисунок 5-23).
766
+
767
+ Insert 18333fig0521.png
768
+ Рисунок 5-21. История коммитов до слияния тематической ветки.
769
+
770
+ Insert 18333fig0522.png
771
+ Рисунок 5-22. История коммитов после слияния тематической ветки.
772
+
773
+ Insert 18333fig0523.png
774
+ Рисунок 5-23. История коммитов после появления релиза.
775
+
776
+ При таком подходе, клонируя ваш репозиторий, люди могут либо выгрузить ветку `master`, чтобы получить последний стабильный релиз и легко поддерживать этот код обновлённым, либо переключиться на ветку `develop`, которая включает в себя всё самое свежее.
777
+ Вы также можете развить данный подход, создав ветку для интегрирования, в которой будет происходить слияние всех наработок. И когда код на этой ветке станет стабилен и пройдёт все тесты, вы сольёте её в ветку `develop`; и если всё будет работать как надо в течение некоторого времени, вы выполните перемотку ветки `master`.
778
+
779
+ #### Рабочие процессы с крупными слияниями ####
780
+
781
+ В проекте Git имеются четыре долгоживущие ветки: `master`, `next`, `pu` (proposed updates) для новых наработок и `maint` для ретроподдержки (backports). Когда участники проекта подготавливают свои наработки, они собираются в тематических ветках в репозитории мейнтейнера проекта примерно так, как мы уже описывали (см. рис. 5-24). На этом этапе проводится оценка проделанной работы — всё ли работает как положено, стабилен ли код, или ему требуется доработка. Если всё в порядке, то тематические ветки сливаются в ветку `next`, которая отправляется на сервер, чтобы у каждого была возможность опробовать интегрированные воедино изменения из тематических веток.
782
+
783
+ Insert 18333fig0524.png
784
+ Рисунок 5-24. Управление группой параллельных тематических веток участников проекта.
785
+
786
+ Если тематические ветки требуют доработки, они сливаются в ветку `pu`. Когда будет установлено, что тематические ветки полностью стабильны, они переливаются в `master`, а ветки `pu` и `next` перестраиваются на основе тематических веток, находившихся в `next`, но ещё не дозревших до `master`. Это означает, что `master` практически всегда движется в прямом направлении, ветка `next` перемещается (rebase) иногда, а ветка `pu` перемещается чаще всех (см. рис. 5-25).
787
+
788
+ Insert 18333fig0525.png
789
+ Рисунок 5-25. Слияние тематических веток участников проекта в долгоживущие интеграционные ветки.
790
+
791
+ Когда тематическая ветка была полностью слита в ветку `master`, она удаляется из репозитория. В проекте Git есть ещё ветка `maint`, которая ответвлена от последнего релиза и предоставляет backport-патчи, на случай если потребуется выпуск корректировочной версии. Таким образом, когда вы клонируете Git-репозиторий, вы получаете четыре ветки, переключаясь на которые вы можете оценить проект на разных стадиях разработки (в зависимости от того, насколько свежую версию вы хотите получить, или от того, каким образом вы хотите внести в проект свою работу); а мейнтейнер, в свою очередь, имеет структурированный рабочий процесс, который помогает ему изучать новые присланные патчи.
792
+
793
+ #### Рабочие процессы с перемещениями и отбором лучшего ####
794
+
795
+ Другие мейнтейнеры вместо слияния предпочитают выполнять перемещение или отбор лучших наработок участников проекта на верхушку своей ветки `master`, чтобы иметь практически линейную историю разработки. Когда у вас есть наработки в тематической ветке, которые вы хотите интегрировать в проект, вы переходите на эту ветку и запускаете команду `rebase`, которая перемещает изменения на верхушку вашей текущей ветки `master` (или `develop`, и т.п.). Если всё прошло хорошо, то можете выполнить перемотку ветки `master`, получив тем самым линейную историю работы над проектом.
796
+
797
+ Другой вариант перемещения сделанных наработок из одной ветки в другую — отбор лучшего (cherry-pick). Отбор лучшего в Git'е является чем-то наподобие перемещения для отдельных коммитов. Берётся патч, который был представлен в коммите, и делается попытка применить его на ветке, на которой вы сейчас находитесь. Это удобно в том случае, если у вас в тематической ветке находится несколько коммитов, а вы хотите включить в проект только один из них, или если у вас только один коммит в тематической ветке, но вы предпочитаете выполнять отбор лучшего вместо перемещения. Например, предположим, ваш проект выглядит так, как показано на рисунке 5-26.
798
+
799
+ Insert 18333fig0526.png
800
+ Рисунок 5-26. Пример истории коммитов перед отбором лучшего.
801
+
802
+ Если вы хотите вытащить коммит `e43a6` в ветку `master`, выполните:
803
+
804
+ $ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf
805
+ Finished one cherry-pick.
806
+ [master]: created a0a41a9: "More friendly message when locking the index fails."
807
+ 3 files changed, 17 insertions(+), 3 deletions(-)
808
+
809
+ Эта команда включит в ветку `master` такие же изменения, которые были добавлены в `e43a6`, но вы получите новое значение SHA-1 для этого коммита, так как у него будет другая дата применения. Теперь ваша история коммитов выглядит, как показано на рисунке 5-27.
810
+
811
+ Insert 18333fig0527.png
812
+ Рисунок 5-27. История коммитов после отбора лучшего коммита из тематической ветки.
813
+
814
+ Теперь вы можете удалить свою тематическую ветку и отбросить коммиты, которые вы не захотели включить в проект.
815
+
816
+ ### Отметка релизов ###
817
+
818
+ Если вы решили выпустить релиз, вы, вероятно, захотите присвоить ему метку, так чтобы вы потом смогли восстановить этот релиз в любой момент. Процесс создания новой метки обсуждался в главе 2. Если вы решили подписать вашу метку как мейнтейнер, то процедура будет выглядеть примерно следующим образом:
819
+
820
+ $ git tag -s v1.5 -m 'my signed 1.5 tag'
821
+ You need a passphrase to unlock the secret key for
822
+ user: "Scott Chacon <schacon@gmail.com>"
823
+ 1024-bit DSA key, ID F721C45A, created 2009-02-09
824
+
825
+ Если вы подписываете свои метки, у вас может возникнуть проблема с распространением открытого PGP-ключа, используемого для подписи ваших меток. Мейнтейнер проекта Git решил эту проблему, добавив свой публичный ключ в виде блоба (blob) прямо в репозиторий и затем выставив метку, указывающую прямо на содержимое ключа. Чтобы сделать это, определите, какой ключ вам нужен, выполнив `gpg --list-keys`:
826
+
827
+ $ gpg --list-keys
828
+ /Users/schacon/.gnupg/pubring.gpg
829
+ ---------------------------------
830
+ pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
831
+ uid Scott Chacon <schacon@gmail.com>
832
+ sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
833
+
834
+ Затем вы можете напрямую импортировать ключ в базу данных Git'а, экспортировав его и передав по конвейеру команде `git hash-object`, которая создаст новый блоб с содержимым ключа и вернёт вам SHA-1 этого блоба:
835
+
836
+ $ gpg -a --export F721C45A | git hash-object -w --stdin
837
+ 659ef797d181633c87ec71ac3f9ba29fe5775b92
838
+
839
+ Теперь, когда у вас в Git'е хранится ваш ключ, вы можете создать метку, напрямую указывающую на него, использовав значение SHA-1, возвращённое командой `hash-object`:
840
+
841
+ $ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
842
+
843
+ Если вы запустите команду `git push --tags`, то метка `maintainer-pgp-pub` станет доступна каждому. Если кто-нибудь захочет проверить какую-нибудь метку, он сможет напрямую импортировать ваш PGP-ключ, вытащив блоб прямо из базы данных и импортировав его в GPG:
844
+
845
+ $ git show maintainer-pgp-pub | gpg --import
846
+
847
+ Этот ключ может быть использован для проверки любых подписанных вами меток. Кроме того, если вы включите инструкции в сообщение метки, запуск `git show <метка>` позволит конечному пользователю получить инструкции по проверке меток.
848
+
849
+ ### Генерация номера сборки ###
850
+
851
+ Так как коммитам в Git'е не присваиваются монотонно возрастающие номера наподобие 'v123' или чего-то аналогичного, то в случае, если вы хотите присвоить коммиту имя, удобное для восприятия, запустите команду `git describe` для этого коммита. Git вернёт вам имя ближайшей метки с числом коммитов, сделанных поверх этой метки и частичное значения SHA-1 описываемого коммита:
852
+
853
+ $ git describe master
854
+ v1.6.2-rc1-20-g8c5b85c
855
+
856
+ Таким образом, при экспорте снимка состояния проекта или его сборки вы можете дать им имя, понятное для людей. На самом деле, если вы собираете Git из исходного кода, склонированного из Git-репозитория, `git --version` вернёт вам что-то подобное. Если вы описываете коммит, которому вы напрямую присвоили метку, команда вернёт вам имя метки.
857
+
858
+ Команду `git describe` хорошо использовать с аннотированными метками (метками, созданными при помощи опций `-a` или `-s`), так что если вы используете `git describe`, то метки для релизов должны создаваться этим способом — в этом случае вы сможете удостовериться, что при описании коммиту было дано правильное имя. Вы также можете использовать эту строку в командах `checkout` и `show` для указания нужного коммита, однако в будущем она может перестать работать правильно в силу того, что в строке присутствует сокращённое значение SHA-1. Например, в ядре Linux недавно перешли от 8 к 10 символам, необходимым для обеспечения уникальности SHA-1 объектов, и поэтому старые имена, сгенерированные командой `git describe`, стали недействительными.
859
+
860
+ ### Подготовка релиза ###
861
+
862
+ Теперь хотелось бы выпустить релиз сборки. Вероятно, вам захочется сделать архив последнего состояния вашего кода для тех бедолаг, которые не используют Git. Для этого используется команда `git archive`:
863
+
864
+ $ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
865
+ $ ls *.tar.gz
866
+ v1.6.2-rc1-20-g8c5b85c.tar.gz
867
+
868
+ Если кто-нибудь откроет этот tarball, он получит последний снимок состояния вашего проекта внутри каталога `project`. Таким же способом вы можете создать zip-архив, указав команде `git archive` опцию `--format=zip`:
869
+
870
+ $ git archive master --prefix='project/' --format=zip > `git describe master`.zip
871
+
872
+ Теперь у вас есть тарбол и zip-архив с релизом вашего проекта, которые вы можете загрузить на свой сайт или отправить людям по почте.
873
+
874
+ ### Команда shortlog ###
875
+
876
+ Пришло время написать письмо для списка рассылки, чтобы поделиться новостями проекта со всеми, кто им интересуется. При помощи команды `git shortlog` можно быстро получить что-то наподобие лога изменений (changelog), описывающего, что появилось нового в вашем проекте со времени последнего релиза или последнего письма в список рассылки. Лог изменений включает в себя все коммиты в указанном диапазоне; например, следующая команда вернёт вам сводку по всем коммитам, сделанным со времени прошлого релиза (если последний релиз имел метку v1.0.1):
877
+
878
+ $ git shortlog --no-merges master --not v1.0.1
879
+ Chris Wanstrath (8):
880
+ Add support for annotated tags to Grit::Tag
881
+ Add packed-refs annotated tag support.
882
+ Add Grit::Commit#to_patch
883
+ Update version and History.txt
884
+ Remove stray `puts`
885
+ Make ls_tree ignore nils
886
+
887
+ Tom Preston-Werner (4):
888
+ fix dates in history
889
+ dynamic version method
890
+ Version bump to 1.0.2
891
+ Regenerated gemspec for version 1.0.2
892
+
893
+ Мы получили аккуратную сводку по всем коммитам, начиная с метки v1.0.1, сгруппированным по авторам. Вывод этой команды можно послать в свой список рассылки.
894
+
895
+ ## Итоги ##
896
+
897
+ Вы должны чувствовать себя достаточно свободно, внося свой вклад в проект под управлением Git'а, а также занимаясь поддержкой своего собственного проекта или интегрированием наработок других пользователей. Поздравляем тебя, опытный Git-разработчик! В следующей главе вы познакомитесь с более мощными инструментами, а также получите советы по действию в сложных ситуациях, что сделает из вас настоящего мастера Git'а.