wayfarer 0.4.0 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (742) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +1 -1
  3. data/.rubocop.yml +10 -0
  4. data/Gemfile.lock +21 -16
  5. data/docs/cookbook/batch_routing.md +22 -0
  6. data/docs/cookbook/consent_screen.md +36 -0
  7. data/docs/cookbook/executing_javascript.md +41 -0
  8. data/docs/cookbook/navigation.md +43 -0
  9. data/docs/cookbook/querying_html.md +3 -3
  10. data/docs/cookbook/screenshots.md +2 -2
  11. data/docs/cookbook/user_agent.md +1 -1
  12. data/docs/guides/callbacks.md +122 -15
  13. data/docs/guides/configuration.md +16 -10
  14. data/docs/guides/debugging.md +17 -0
  15. data/docs/guides/error_handling.md +22 -22
  16. data/docs/guides/jobs.md +44 -18
  17. data/docs/guides/navigation.md +73 -0
  18. data/docs/guides/networking/capybara.md +71 -0
  19. data/docs/guides/networking/custom_adapters.md +100 -0
  20. data/docs/guides/{browser_automation → networking}/ferrum.md +6 -4
  21. data/docs/guides/networking/http.md +33 -0
  22. data/docs/guides/{browser_automation → networking}/selenium.md +11 -7
  23. data/docs/guides/networking.md +77 -3
  24. data/docs/guides/pages.md +4 -4
  25. data/docs/guides/performance.md +108 -0
  26. data/docs/guides/reliability.md +41 -0
  27. data/docs/guides/routing/steering.md +30 -0
  28. data/docs/guides/tasks.md +9 -33
  29. data/docs/index.md +9 -1
  30. data/docs/reference/api/base.md +13 -127
  31. data/docs/reference/api/route.md +1 -1
  32. data/docs/reference/cli.md +0 -78
  33. data/docs/reference/configuration_keys.md +42 -0
  34. data/docs/reference/environment_variables.md +25 -27
  35. data/lib/wayfarer/base.rb +32 -32
  36. data/lib/wayfarer/callbacks.rb +71 -0
  37. data/lib/wayfarer/cli/base.rb +23 -1
  38. data/lib/wayfarer/cli/job.rb +7 -9
  39. data/lib/wayfarer/cli/route.rb +6 -4
  40. data/lib/wayfarer/cli/route_printer.rb +7 -7
  41. data/lib/wayfarer/cli/templates/job.rb.tt +3 -1
  42. data/lib/wayfarer/config/capybara.rb +10 -0
  43. data/lib/wayfarer/config/ferrum.rb +11 -0
  44. data/lib/wayfarer/config/networking.rb +26 -0
  45. data/lib/wayfarer/config/redis.rb +14 -0
  46. data/lib/wayfarer/config/root.rb +11 -0
  47. data/lib/wayfarer/config/selenium.rb +21 -0
  48. data/lib/wayfarer/config/strconv.rb +45 -0
  49. data/lib/wayfarer/config/struct.rb +72 -0
  50. data/lib/wayfarer/gc.rb +3 -8
  51. data/lib/wayfarer/handler.rb +15 -0
  52. data/lib/wayfarer/middleware/base.rb +19 -0
  53. data/lib/wayfarer/middleware/chain.rb +8 -0
  54. data/lib/wayfarer/middleware/controller.rb +40 -0
  55. data/lib/wayfarer/middleware/dedup.rb +5 -0
  56. data/lib/wayfarer/middleware/dispatch.rb +22 -0
  57. data/lib/wayfarer/middleware/fetch.rb +35 -11
  58. data/lib/wayfarer/middleware/lazy.rb +11 -0
  59. data/lib/wayfarer/middleware/normalize.rb +2 -0
  60. data/lib/wayfarer/middleware/router.rb +41 -3
  61. data/lib/wayfarer/middleware/stage.rb +6 -2
  62. data/lib/wayfarer/networking/capybara.rb +28 -0
  63. data/lib/wayfarer/networking/context.rb +37 -0
  64. data/lib/wayfarer/networking/ferrum.rb +18 -52
  65. data/lib/wayfarer/networking/follow.rb +22 -0
  66. data/lib/wayfarer/networking/http.rb +34 -0
  67. data/lib/wayfarer/networking/pool.rb +20 -14
  68. data/lib/wayfarer/networking/result.rb +1 -9
  69. data/lib/wayfarer/networking/selenium.rb +20 -47
  70. data/lib/wayfarer/networking/strategy.rb +38 -0
  71. data/lib/wayfarer/page.rb +3 -4
  72. data/lib/wayfarer/redis/pool.rb +3 -1
  73. data/lib/wayfarer/routing/dsl.rb +8 -8
  74. data/lib/wayfarer/routing/matchers/custom.rb +25 -0
  75. data/lib/wayfarer/routing/matchers/host.rb +21 -0
  76. data/lib/wayfarer/routing/matchers/path.rb +49 -0
  77. data/lib/wayfarer/routing/matchers/query.rb +63 -0
  78. data/lib/wayfarer/routing/matchers/scheme.rb +17 -0
  79. data/lib/wayfarer/routing/matchers/suffix.rb +17 -0
  80. data/lib/wayfarer/routing/matchers/url.rb +17 -0
  81. data/lib/wayfarer/routing/result.rb +0 -5
  82. data/lib/wayfarer/routing/route.rb +7 -1
  83. data/lib/wayfarer/routing/router.rb +28 -0
  84. data/lib/wayfarer/stringify.rb +13 -7
  85. data/lib/wayfarer/task.rb +4 -2
  86. data/lib/wayfarer.rb +5 -10
  87. data/spec/base_spec.rb +45 -40
  88. data/spec/callbacks_spec.rb +102 -0
  89. data/spec/cli/job_spec.rb +11 -7
  90. data/spec/config/capybara_spec.rb +18 -0
  91. data/spec/config/ferrum_spec.rb +24 -0
  92. data/spec/config/networking_spec.rb +73 -0
  93. data/spec/config/redis_spec.rb +32 -0
  94. data/spec/config/root_spec.rb +31 -0
  95. data/spec/config/selenium_spec.rb +56 -0
  96. data/spec/config/strconv_spec.rb +58 -0
  97. data/spec/config/struct_spec.rb +66 -0
  98. data/spec/factories/{queue/middleware.rb → middleware.rb} +3 -3
  99. data/spec/factories/{queue/page.rb → page.rb} +3 -3
  100. data/spec/factories/{queue/task.rb → task.rb} +0 -0
  101. data/spec/fixtures/dummy_job.rb +1 -1
  102. data/spec/gc_spec.rb +5 -7
  103. data/spec/handler_spec.rb +11 -0
  104. data/spec/integration/callbacks_spec.rb +85 -0
  105. data/spec/integration/page_spec.rb +62 -0
  106. data/spec/integration/params_spec.rb +56 -0
  107. data/spec/integration/stage_spec.rb +51 -0
  108. data/spec/integration/steering_spec.rb +57 -0
  109. data/spec/middleware/chain_spec.rb +32 -19
  110. data/spec/middleware/controller_spec.rb +86 -0
  111. data/spec/middleware/dedup_spec.rb +20 -8
  112. data/spec/middleware/dispatch_spec.rb +43 -0
  113. data/spec/middleware/fetch_spec.rb +117 -34
  114. data/spec/middleware/normalize_spec.rb +5 -4
  115. data/spec/middleware/router_spec.rb +82 -23
  116. data/spec/middleware/stage_spec.rb +42 -19
  117. data/spec/networking/capybara_spec.rb +12 -0
  118. data/spec/networking/context_spec.rb +127 -0
  119. data/spec/networking/ferrum_spec.rb +6 -22
  120. data/spec/networking/follow_spec.rb +41 -0
  121. data/spec/networking/http_spec.rb +12 -0
  122. data/spec/networking/pool_spec.rb +37 -12
  123. data/spec/networking/selenium_spec.rb +6 -22
  124. data/spec/networking/strategy.rb +170 -0
  125. data/spec/redis/pool_spec.rb +1 -1
  126. data/spec/routing/dsl_spec.rb +10 -10
  127. data/spec/routing/integration_spec.rb +22 -22
  128. data/spec/routing/{custom_matcher_spec.rb → matchers/custom_spec.rb} +4 -4
  129. data/spec/routing/{host_matcher_spec.rb → matchers/host_spec.rb} +6 -6
  130. data/spec/routing/{path_matcher_spec.rb → matchers/path_spec.rb} +6 -6
  131. data/spec/routing/{query_matcher_spec.rb → matchers/query_spec.rb} +15 -15
  132. data/spec/routing/{scheme_matcher_spec.rb → matchers/scheme_spec.rb} +4 -4
  133. data/spec/routing/{suffix_matcher_spec.rb → matchers/suffix_spec.rb} +4 -4
  134. data/spec/routing/{uri_matcher_spec.rb → matchers/uri_spec.rb} +4 -4
  135. data/spec/routing/path_finder_spec.rb +1 -1
  136. data/spec/routing/root_route_spec.rb +2 -2
  137. data/spec/routing/route_spec.rb +2 -2
  138. data/spec/routing/router_spec.rb +24 -0
  139. data/spec/spec_helpers.rb +24 -8
  140. data/spec/support/static/git-scm.com/assets/application-38b0d42ff05ffea45841edebbd14b75b89585646153808e82907c2c5c11f324b.js +772 -0
  141. data/spec/support/static/git-scm.com/assets/application-cafcf280f67db0e6d8168ba98a38da878769a9d5f37793b68ffb963a02d185e0.css +1 -0
  142. data/spec/support/static/git-scm.com/assets/modernize-b3ebe0c31c24f230dc62179d3e1030d2e57a53b1668d9382c0a27dbd44a94beb.js +20 -0
  143. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Bash.html +751 -0
  144. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-PowerShell.html +804 -0
  145. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Sublime-Text.html +728 -0
  146. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio-Code.html +751 -0
  147. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio.html +740 -0
  148. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Zsh.html +765 -0
  149. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces.html +931 -0
  150. data/spec/support/static/git-scm.com/book/en/v2/Appendix-A:-Git-in-Other-Environments-Summary.html +702 -0
  151. data/spec/support/static/git-scm.com/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git.html +720 -0
  152. data/spec/support/static/git-scm.com/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Dulwich.html +746 -0
  153. data/spec/support/static/git-scm.com/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-JGit.html +889 -0
  154. data/spec/support/static/git-scm.com/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Libgit2.html +1003 -0
  155. data/spec/support/static/git-scm.com/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-go-git.html +792 -0
  156. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Administration.html +745 -0
  157. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Basic-Snapshotting.html +840 -0
  158. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Branching-and-Merging.html +829 -0
  159. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Debugging.html +731 -0
  160. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Email.html +766 -0
  161. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-External-Systems.html +721 -0
  162. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Getting-and-Creating-Projects.html +746 -0
  163. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Inspection-and-Comparison.html +735 -0
  164. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Patching.html +742 -0
  165. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Plumbing-Commands.html +715 -0
  166. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Setup-and-Config.html +863 -0
  167. data/spec/support/static/git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Sharing-and-Updating-Projects.html +802 -0
  168. data/spec/support/static/git-scm.com/book/en/v2/Customizing-Git-An-Example-Git-Enforced-Policy.html +1200 -0
  169. data/spec/support/static/git-scm.com/book/en/v2/Customizing-Git-Git-Attributes.html +1134 -0
  170. data/spec/support/static/git-scm.com/book/en/v2/Customizing-Git-Git-Configuration.html +1315 -0
  171. data/spec/support/static/git-scm.com/book/en/v2/Customizing-Git-Git-Hooks.html +876 -0
  172. data/spec/support/static/git-scm.com/book/en/v2/Customizing-Git-Summary.html +704 -0
  173. data/spec/support/static/git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project.html +1667 -0
  174. data/spec/support/static/git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows.html +859 -0
  175. data/spec/support/static/git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project.html +1354 -0
  176. data/spec/support/static/git-scm.com/book/en/v2/Distributed-Git-Summary.html +704 -0
  177. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-A-Short-History-of-Git.html +735 -0
  178. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-About-Version-Control.html +783 -0
  179. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup.html +889 -0
  180. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-Getting-Help.html +750 -0
  181. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-Installing-Git.html +879 -0
  182. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-Summary.html +704 -0
  183. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-The-Command-Line.html +711 -0
  184. data/spec/support/static/git-scm.com/book/en/v2/Getting-Started-What-is-Git?.html +857 -0
  185. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository.html +816 -0
  186. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Git-Aliases.html +775 -0
  187. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository.html +1432 -0
  188. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Summary.html +703 -0
  189. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Tagging.html +1049 -0
  190. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Undoing-Things.html +998 -0
  191. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History.html +1172 -0
  192. data/spec/support/static/git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes.html +983 -0
  193. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging.html +1102 -0
  194. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Branch-Management.html +946 -0
  195. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell.html +1020 -0
  196. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Branching-Workflows.html +786 -0
  197. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Rebasing.html +1028 -0
  198. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Remote-Branches.html +1009 -0
  199. data/spec/support/static/git-scm.com/book/en/v2/Git-Branching-Summary.html +705 -0
  200. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Environment-Variables.html +1009 -0
  201. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Git-Objects.html +1209 -0
  202. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Git-References.html +939 -0
  203. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery.html +1086 -0
  204. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Packfiles.html +876 -0
  205. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain.html +745 -0
  206. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Summary.html +708 -0
  207. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-The-Refspec.html +872 -0
  208. data/spec/support/static/git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols.html +1043 -0
  209. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Advanced-Merging.html +1605 -0
  210. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Bundling.html +888 -0
  211. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Credential-Storage.html +1035 -0
  212. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git.html +861 -0
  213. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Interactive-Staging.html +920 -0
  214. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Replace.html +949 -0
  215. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Rerere.html +983 -0
  216. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Reset-Demystified.html +1236 -0
  217. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Revision-Selection.html +1178 -0
  218. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Rewriting-History.html +1182 -0
  219. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Searching.html +875 -0
  220. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work.html +922 -0
  221. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning.html +1039 -0
  222. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Submodules.html +1864 -0
  223. data/spec/support/static/git-scm.com/book/en/v2/Git-Tools-Summary.html +705 -0
  224. data/spec/support/static/git-scm.com/book/en/v2/Git-and-Other-Systems-Git-as-a-Client.html +2656 -0
  225. data/spec/support/static/git-scm.com/book/en/v2/Git-and-Other-Systems-Migrating-to-Git.html +1741 -0
  226. data/spec/support/static/git-scm.com/book/en/v2/Git-and-Other-Systems-Summary.html +703 -0
  227. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key.html +759 -0
  228. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server.html +827 -0
  229. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon.html +775 -0
  230. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-GitLab.html +872 -0
  231. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-GitWeb.html +776 -0
  232. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server.html +870 -0
  233. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Smart-HTTP.html +789 -0
  234. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Summary.html +709 -0
  235. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols.html +963 -0
  236. data/spec/support/static/git-scm.com/book/en/v2/Git-on-the-Server-Third-Party-Hosted-Options.html +711 -0
  237. data/spec/support/static/git-scm.com/book/en/v2/GitHub-Account-Setup-and-Configuration.html +858 -0
  238. data/spec/support/static/git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project.html +1502 -0
  239. data/spec/support/static/git-scm.com/book/en/v2/GitHub-Maintaining-a-Project.html +1218 -0
  240. data/spec/support/static/git-scm.com/book/en/v2/GitHub-Managing-an-organization.html +797 -0
  241. data/spec/support/static/git-scm.com/book/en/v2/GitHub-Scripting-GitHub.html +1059 -0
  242. data/spec/support/static/git-scm.com/book/en/v2/GitHub-Summary.html +704 -0
  243. data/spec/support/static/git-scm.com/book/en/v2/ch00/_abort_merge.html +1605 -0
  244. data/spec/support/static/git-scm.com/book/en/v2/ch00/_add_email_addresses.html +858 -0
  245. data/spec/support/static/git-scm.com/book/en/v2/ch00/_advanced_merging.html +1605 -0
  246. data/spec/support/static/git-scm.com/book/en/v2/ch00/_an_example_git_enforced_policy.html +1200 -0
  247. data/spec/support/static/git-scm.com/book/en/v2/ch00/_annotated_tags.html +1049 -0
  248. data/spec/support/static/git-scm.com/book/en/v2/ch00/_api_comment.html +1059 -0
  249. data/spec/support/static/git-scm.com/book/en/v2/ch00/_bare_repo.html +827 -0
  250. data/spec/support/static/git-scm.com/book/en/v2/ch00/_basic_branching.html +1102 -0
  251. data/spec/support/static/git-scm.com/book/en/v2/ch00/_basic_merge_conflicts.html +1102 -0
  252. data/spec/support/static/git-scm.com/book/en/v2/ch00/_basic_merging.html +1102 -0
  253. data/spec/support/static/git-scm.com/book/en/v2/ch00/_binary_search.html +861 -0
  254. data/spec/support/static/git-scm.com/book/en/v2/ch00/_branch_management.html +946 -0
  255. data/spec/support/static/git-scm.com/book/en/v2/ch00/_branch_references.html +1178 -0
  256. data/spec/support/static/git-scm.com/book/en/v2/ch00/_build_number.html +1354 -0
  257. data/spec/support/static/git-scm.com/book/en/v2/ch00/_bundling.html +888 -0
  258. data/spec/support/static/git-scm.com/book/en/v2/ch00/_changing_multiple.html +1182 -0
  259. data/spec/support/static/git-scm.com/book/en/v2/ch00/_checking_out_conflicts.html +1605 -0
  260. data/spec/support/static/git-scm.com/book/en/v2/ch00/_checking_out_remotes.html +1354 -0
  261. data/spec/support/static/git-scm.com/book/en/v2/ch00/_checking_status.html +1432 -0
  262. data/spec/support/static/git-scm.com/book/en/v2/ch00/_cloning_submodules.html +1864 -0
  263. data/spec/support/static/git-scm.com/book/en/v2/ch00/_commit_guidelines.html +1667 -0
  264. data/spec/support/static/git-scm.com/book/en/v2/ch00/_commit_ranges.html +1178 -0
  265. data/spec/support/static/git-scm.com/book/en/v2/ch00/_commit_status.html +1059 -0
  266. data/spec/support/static/git-scm.com/book/en/v2/ch00/_committing_changes.html +1432 -0
  267. data/spec/support/static/git-scm.com/book/en/v2/ch00/_contrib_file.html +1218 -0
  268. data/spec/support/static/git-scm.com/book/en/v2/ch00/_contributing_project.html +1667 -0
  269. data/spec/support/static/git-scm.com/book/en/v2/ch00/_create_new_branch.html +1020 -0
  270. data/spec/support/static/git-scm.com/book/en/v2/ch00/_credential_caching.html +1035 -0
  271. data/spec/support/static/git-scm.com/book/en/v2/ch00/_custom_importer.html +1741 -0
  272. data/spec/support/static/git-scm.com/book/en/v2/ch00/_data_recovery.html +1086 -0
  273. data/spec/support/static/git-scm.com/book/en/v2/ch00/_delete_branches.html +1009 -0
  274. data/spec/support/static/git-scm.com/book/en/v2/ch00/_editor.html +889 -0
  275. data/spec/support/static/git-scm.com/book/en/v2/ch00/_eg_task_lists.html +1502 -0
  276. data/spec/support/static/git-scm.com/book/en/v2/ch00/_email_hooks.html +876 -0
  277. data/spec/support/static/git-scm.com/book/en/v2/ch00/_email_notification.html +1502 -0
  278. data/spec/support/static/git-scm.com/book/en/v2/ch00/_email_notifications.html +1218 -0
  279. data/spec/support/static/git-scm.com/book/en/v2/ch00/_email_pr.html +1218 -0
  280. data/spec/support/static/git-scm.com/book/en/v2/ch00/_enforcing_commit_message_format.html +1200 -0
  281. data/spec/support/static/git-scm.com/book/en/v2/ch00/_example_markdown.html +1502 -0
  282. data/spec/support/static/git-scm.com/book/en/v2/ch00/_external_merge_tools.html +1315 -0
  283. data/spec/support/static/git-scm.com/book/en/v2/ch00/_fetch_and_push_on_different_repositories.html +1502 -0
  284. data/spec/support/static/git-scm.com/book/en/v2/ch00/_fetching_and_pulling.html +983 -0
  285. data/spec/support/static/git-scm.com/book/en/v2/ch00/_file_annotation.html +861 -0
  286. data/spec/support/static/git-scm.com/book/en/v2/ch00/_first_time.html +889 -0
  287. data/spec/support/static/git-scm.com/book/en/v2/ch00/_generate_ssh_key.html +759 -0
  288. data/spec/support/static/git-scm.com/book/en/v2/ch00/_getting_a_repo.html +816 -0
  289. data/spec/support/static/git-scm.com/book/en/v2/ch00/_getting_git_on_a_server.html +827 -0
  290. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_aliases.html +775 -0
  291. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_am.html +1354 -0
  292. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_amend.html +1182 -0
  293. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_branches_overview.html +1020 -0
  294. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_clean.html +1039 -0
  295. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_cloning.html +816 -0
  296. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_commit_objects.html +1209 -0
  297. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_config.html +1315 -0
  298. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_diff_staged.html +1432 -0
  299. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_gc.html +1086 -0
  300. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_grep.html +875 -0
  301. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_help.html +750 -0
  302. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_hooks.html +876 -0
  303. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_mv.html +1432 -0
  304. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_p4.html +1741 -0
  305. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_p4_branches.html +2656 -0
  306. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_reflog.html +1178 -0
  307. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_refs.html +939 -0
  308. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_reset.html +1236 -0
  309. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_stashing.html +1039 -0
  310. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_submodules.html +1864 -0
  311. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_svn.html +2656 -0
  312. data/spec/support/static/git-scm.com/book/en/v2/ch00/_git_tagging.html +1049 -0
  313. data/spec/support/static/git-scm.com/book/en/v2/ch00/_gitlab_groups_section.html +872 -0
  314. data/spec/support/static/git-scm.com/book/en/v2/ch00/_ignoring.html +1432 -0
  315. data/spec/support/static/git-scm.com/book/en/v2/ch00/_inspecting_remote.html +983 -0
  316. data/spec/support/static/git-scm.com/book/en/v2/ch00/_integration_manager.html +859 -0
  317. data/spec/support/static/git-scm.com/book/en/v2/ch00/_interactive_staging.html +920 -0
  318. data/spec/support/static/git-scm.com/book/en/v2/ch00/_keyword_expansion.html +1134 -0
  319. data/spec/support/static/git-scm.com/book/en/v2/ch00/_libgit2_bindings.html +1003 -0
  320. data/spec/support/static/git-scm.com/book/en/v2/ch00/_manual_remerge.html +1605 -0
  321. data/spec/support/static/git-scm.com/book/en/v2/ch00/_md_code.html +1502 -0
  322. data/spec/support/static/git-scm.com/book/en/v2/ch00/_md_drag.html +1502 -0
  323. data/spec/support/static/git-scm.com/book/en/v2/ch00/_md_emoji.html +1502 -0
  324. data/spec/support/static/git-scm.com/book/en/v2/ch00/_md_quote.html +1502 -0
  325. data/spec/support/static/git-scm.com/book/en/v2/ch00/_merge_button.html +1218 -0
  326. data/spec/support/static/git-scm.com/book/en/v2/ch00/_merge_log.html +1605 -0
  327. data/spec/support/static/git-scm.com/book/en/v2/ch00/_merge_rebase_work.html +1028 -0
  328. data/spec/support/static/git-scm.com/book/en/v2/ch00/_new_repo_dropdown.html +1218 -0
  329. data/spec/support/static/git-scm.com/book/en/v2/ch00/_not_center.html +1218 -0
  330. data/spec/support/static/git-scm.com/book/en/v2/ch00/_org_page.html +797 -0
  331. data/spec/support/static/git-scm.com/book/en/v2/ch00/_other_client_hooks.html +876 -0
  332. data/spec/support/static/git-scm.com/book/en/v2/ch00/_p4_git_fusion.html +2656 -0
  333. data/spec/support/static/git-scm.com/book/en/v2/ch00/_patches_from_email.html +1354 -0
  334. data/spec/support/static/git-scm.com/book/en/v2/ch00/_personal_avatar.html +858 -0
  335. data/spec/support/static/git-scm.com/book/en/v2/ch00/_plumbing_porcelain.html +745 -0
  336. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_closed.html +1502 -0
  337. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_discussion.html +1502 -0
  338. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_fail.html +1502 -0
  339. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_final.html +1502 -0
  340. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_references.html +1502 -0
  341. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_references_render.html +1502 -0
  342. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pr_refs.html +1218 -0
  343. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pre_merge_rebase_work.html +1028 -0
  344. data/spec/support/static/git-scm.com/book/en/v2/ch00/_preparing_release.html +1354 -0
  345. data/spec/support/static/git-scm.com/book/en/v2/ch00/_private_team.html +1667 -0
  346. data/spec/support/static/git-scm.com/book/en/v2/ch00/_project_over_email.html +1667 -0
  347. data/spec/support/static/git-scm.com/book/en/v2/ch00/_public_project.html +1667 -0
  348. data/spec/support/static/git-scm.com/book/en/v2/ch00/_publishing_submodules.html +1864 -0
  349. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pushing_branches.html +1009 -0
  350. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pushing_refspecs.html +872 -0
  351. data/spec/support/static/git-scm.com/book/en/v2/ch00/_pushing_remotes.html +983 -0
  352. data/spec/support/static/git-scm.com/book/en/v2/ch00/_rebase_cherry_pick.html +1354 -0
  353. data/spec/support/static/git-scm.com/book/en/v2/ch00/_rebase_peril.html +1028 -0
  354. data/spec/support/static/git-scm.com/book/en/v2/ch00/_rebase_rebase.html +1028 -0
  355. data/spec/support/static/git-scm.com/book/en/v2/ch00/_rebase_rebase_work.html +1028 -0
  356. data/spec/support/static/git-scm.com/book/en/v2/ch00/_rebasing.html +1028 -0
  357. data/spec/support/static/git-scm.com/book/en/v2/ch00/_refspec.html +872 -0
  358. data/spec/support/static/git-scm.com/book/en/v2/ch00/_remote_branches.html +1009 -0
  359. data/spec/support/static/git-scm.com/book/en/v2/ch00/_remote_repos.html +983 -0
  360. data/spec/support/static/git-scm.com/book/en/v2/ch00/_removing_file_every_commit.html +1182 -0
  361. data/spec/support/static/git-scm.com/book/en/v2/ch00/_removing_files.html +1432 -0
  362. data/spec/support/static/git-scm.com/book/en/v2/ch00/_removing_objects.html +1086 -0
  363. data/spec/support/static/git-scm.com/book/en/v2/ch00/_replace.html +949 -0
  364. data/spec/support/static/git-scm.com/book/en/v2/ch00/_reverse_commit.html +1605 -0
  365. data/spec/support/static/git-scm.com/book/en/v2/ch00/_revision_selection.html +1178 -0
  366. data/spec/support/static/git-scm.com/book/en/v2/ch00/_rewriting_history.html +1182 -0
  367. data/spec/support/static/git-scm.com/book/en/v2/ch00/_searching.html +875 -0
  368. data/spec/support/static/git-scm.com/book/en/v2/ch00/_service_config.html +1059 -0
  369. data/spec/support/static/git-scm.com/book/en/v2/ch00/_services_hooks.html +1059 -0
  370. data/spec/support/static/git-scm.com/book/en/v2/ch00/_setting_up_server.html +870 -0
  371. data/spec/support/static/git-scm.com/book/en/v2/ch00/_sharing_tags.html +1049 -0
  372. data/spec/support/static/git-scm.com/book/en/v2/ch00/_signing.html +922 -0
  373. data/spec/support/static/git-scm.com/book/en/v2/ch00/_signing_commits.html +922 -0
  374. data/spec/support/static/git-scm.com/book/en/v2/ch00/_squashing.html +1182 -0
  375. data/spec/support/static/git-scm.com/book/en/v2/ch00/_starting_submodules.html +1864 -0
  376. data/spec/support/static/git-scm.com/book/en/v2/ch00/_subtree_merge.html +1605 -0
  377. data/spec/support/static/git-scm.com/book/en/v2/ch00/_switching_branches.html +1020 -0
  378. data/spec/support/static/git-scm.com/book/en/v2/ch00/_tagging_releases.html +1354 -0
  379. data/spec/support/static/git-scm.com/book/en/v2/ch00/_task_list_progress.html +1502 -0
  380. data/spec/support/static/git-scm.com/book/en/v2/ch00/_team_page.html +797 -0
  381. data/spec/support/static/git-scm.com/book/en/v2/ch00/_the_index.html +1236 -0
  382. data/spec/support/static/git-scm.com/book/en/v2/ch00/_the_shortlog.html +1354 -0
  383. data/spec/support/static/git-scm.com/book/en/v2/ch00/_topic_branch.html +786 -0
  384. data/spec/support/static/git-scm.com/book/en/v2/ch00/_tracking_branches.html +1009 -0
  385. data/spec/support/static/git-scm.com/book/en/v2/ch00/_tracking_files.html +1432 -0
  386. data/spec/support/static/git-scm.com/book/en/v2/ch00/_tree_objects.html +1209 -0
  387. data/spec/support/static/git-scm.com/book/en/v2/ch00/_triple_dot.html +1178 -0
  388. data/spec/support/static/git-scm.com/book/en/v2/ch00/_undoing.html +998 -0
  389. data/spec/support/static/git-scm.com/book/en/v2/ch00/_unstaging.html +998 -0
  390. data/spec/support/static/git-scm.com/book/en/v2/ch00/_viewing_history.html +1172 -0
  391. data/spec/support/static/git-scm.com/book/en/v2/ch00/_web_hook.html +1059 -0
  392. data/spec/support/static/git-scm.com/book/en/v2/ch00/_what_is_introduced.html +1354 -0
  393. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch01-getting-started.html +783 -0
  394. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch02-git-basics-chapter.html +816 -0
  395. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch03-git-branching.html +1020 -0
  396. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch05-distributed-git.html +859 -0
  397. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch06-github.html +858 -0
  398. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch06-github_flow.html +1502 -0
  399. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch10-git-internals.html +745 -0
  400. data/spec/support/static/git-scm.com/book/en/v2/ch00/ch_core_editor.html +863 -0
  401. data/spec/support/static/git-scm.com/book/en/v2/ch00/divergent_history.html +1020 -0
  402. data/spec/support/static/git-scm.com/book/en/v2/ch00/double_dot.html +1178 -0
  403. data/spec/support/static/git-scm.com/book/en/v2/ch00/filters_a.html +1134 -0
  404. data/spec/support/static/git-scm.com/book/en/v2/ch00/filters_b.html +1134 -0
  405. data/spec/support/static/git-scm.com/book/en/v2/ch00/limit_options.html +1172 -0
  406. data/spec/support/static/git-scm.com/book/en/v2/ch00/log_options.html +1172 -0
  407. data/spec/support/static/git-scm.com/book/en/v2/ch00/merwf_a.html +1354 -0
  408. data/spec/support/static/git-scm.com/book/en/v2/ch00/merwf_b.html +1354 -0
  409. data/spec/support/static/git-scm.com/book/en/v2/ch00/merwf_c.html +1354 -0
  410. data/spec/support/static/git-scm.com/book/en/v2/ch00/merwf_d.html +1354 -0
  411. data/spec/support/static/git-scm.com/book/en/v2/ch00/merwf_e.html +1354 -0
  412. data/spec/support/static/git-scm.com/book/en/v2/ch00/merwf_f.html +1354 -0
  413. data/spec/support/static/git-scm.com/book/en/v2/ch00/oh_my_zsh_git.html +765 -0
  414. data/spec/support/static/git-scm.com/book/en/v2/ch00/pretty_format.html +1172 -0
  415. data/spec/support/static/git-scm.com/book/en/v2/ch00/psp_b.html +1667 -0
  416. data/spec/support/static/git-scm.com/book/en/v2/ch00/rbdiag_e.html +1028 -0
  417. data/spec/support/static/git-scm.com/book/en/v2/ch00/rbdiag_g.html +1028 -0
  418. data/spec/support/static/git-scm.com/book/en/v2/ch00/rbdiag_h.html +1028 -0
  419. data/spec/support/static/git-scm.com/book/en/v2/ch00/rbdiag_i.html +1028 -0
  420. data/spec/support/static/git-scm.com/book/en/v2/ch00/rebasing-merging-example.html +1028 -0
  421. data/spec/support/static/git-scm.com/book/en/v2/ch00/ref_rerere.html +983 -0
  422. data/spec/support/static/git-scm.com/book/en/v2/ch00/ref_the_ref.html +939 -0
  423. data/spec/support/static/git-scm.com/book/en/v2/ch00/wfdiag_b.html +859 -0
  424. data/spec/support/static/git-scm.com/book/en/v2/ch00/wfdiag_c.html +859 -0
  425. data/spec/support/static/git-scm.com/book/en/v2/ch00/what_is_git_section.html +857 -0
  426. data/spec/support/static/git-scm.com/book/en/v2/images/2fa-1.png +0 -0
  427. data/spec/support/static/git-scm.com/book/en/v2/images/account-settings.png +0 -0
  428. data/spec/support/static/git-scm.com/book/en/v2/images/advance-master.png +0 -0
  429. data/spec/support/static/git-scm.com/book/en/v2/images/advance-testing.png +0 -0
  430. data/spec/support/static/git-scm.com/book/en/v2/images/areas.png +0 -0
  431. data/spec/support/static/git-scm.com/book/en/v2/images/avatar-crop.png +0 -0
  432. data/spec/support/static/git-scm.com/book/en/v2/images/basic-branching-1.png +0 -0
  433. data/spec/support/static/git-scm.com/book/en/v2/images/basic-branching-2.png +0 -0
  434. data/spec/support/static/git-scm.com/book/en/v2/images/basic-branching-3.png +0 -0
  435. data/spec/support/static/git-scm.com/book/en/v2/images/basic-branching-4.png +0 -0
  436. data/spec/support/static/git-scm.com/book/en/v2/images/basic-branching-5.png +0 -0
  437. data/spec/support/static/git-scm.com/book/en/v2/images/basic-branching-6.png +0 -0
  438. data/spec/support/static/git-scm.com/book/en/v2/images/basic-merging-1.png +0 -0
  439. data/spec/support/static/git-scm.com/book/en/v2/images/basic-merging-2.png +0 -0
  440. data/spec/support/static/git-scm.com/book/en/v2/images/basic-rebase-1.png +0 -0
  441. data/spec/support/static/git-scm.com/book/en/v2/images/basic-rebase-2.png +0 -0
  442. data/spec/support/static/git-scm.com/book/en/v2/images/basic-rebase-3.png +0 -0
  443. data/spec/support/static/git-scm.com/book/en/v2/images/basic-rebase-4.png +0 -0
  444. data/spec/support/static/git-scm.com/book/en/v2/images/benevolent-dictator.png +0 -0
  445. data/spec/support/static/git-scm.com/book/en/v2/images/blink-01-start.png +0 -0
  446. data/spec/support/static/git-scm.com/book/en/v2/images/blink-02-pr.png +0 -0
  447. data/spec/support/static/git-scm.com/book/en/v2/images/blink-03-pull-request-open.png +0 -0
  448. data/spec/support/static/git-scm.com/book/en/v2/images/blink-04-email.png +0 -0
  449. data/spec/support/static/git-scm.com/book/en/v2/images/blink-04-pr-comment.png +0 -0
  450. data/spec/support/static/git-scm.com/book/en/v2/images/blink-05-general-comment.png +0 -0
  451. data/spec/support/static/git-scm.com/book/en/v2/images/blink-06-final.png +0 -0
  452. data/spec/support/static/git-scm.com/book/en/v2/images/branch-and-history.png +0 -0
  453. data/spec/support/static/git-scm.com/book/en/v2/images/branch_widget_mac.png +0 -0
  454. data/spec/support/static/git-scm.com/book/en/v2/images/branch_widget_win.png +0 -0
  455. data/spec/support/static/git-scm.com/book/en/v2/images/centralized.png +0 -0
  456. data/spec/support/static/git-scm.com/book/en/v2/images/centralized_workflow.png +0 -0
  457. data/spec/support/static/git-scm.com/book/en/v2/images/checkout-master.png +0 -0
  458. data/spec/support/static/git-scm.com/book/en/v2/images/clean.png +0 -0
  459. data/spec/support/static/git-scm.com/book/en/v2/images/collaborators.png +0 -0
  460. data/spec/support/static/git-scm.com/book/en/v2/images/commit-and-tree.png +0 -0
  461. data/spec/support/static/git-scm.com/book/en/v2/images/commits-and-parents.png +0 -0
  462. data/spec/support/static/git-scm.com/book/en/v2/images/data-model-1.png +0 -0
  463. data/spec/support/static/git-scm.com/book/en/v2/images/data-model-2.png +0 -0
  464. data/spec/support/static/git-scm.com/book/en/v2/images/data-model-3.png +0 -0
  465. data/spec/support/static/git-scm.com/book/en/v2/images/data-model-4.png +0 -0
  466. data/spec/support/static/git-scm.com/book/en/v2/images/deltas.png +0 -0
  467. data/spec/support/static/git-scm.com/book/en/v2/images/distributed.png +0 -0
  468. data/spec/support/static/git-scm.com/book/en/v2/images/double-dot.png +0 -0
  469. data/spec/support/static/git-scm.com/book/en/v2/images/email-settings.png +0 -0
  470. data/spec/support/static/git-scm.com/book/en/v2/images/forkbutton.png +0 -0
  471. data/spec/support/static/git-scm.com/book/en/v2/images/git-bash.png +0 -0
  472. data/spec/support/static/git-scm.com/book/en/v2/images/git-diff-check.png +0 -0
  473. data/spec/support/static/git-scm.com/book/en/v2/images/git-fusion-boot.png +0 -0
  474. data/spec/support/static/git-scm.com/book/en/v2/images/git-fusion-perforce-graph.png +0 -0
  475. data/spec/support/static/git-scm.com/book/en/v2/images/git-gui.png +0 -0
  476. data/spec/support/static/git-scm.com/book/en/v2/images/git-instaweb.png +0 -0
  477. data/spec/support/static/git-scm.com/book/en/v2/images/git-osx-installer.png +0 -0
  478. data/spec/support/static/git-scm.com/book/en/v2/images/github_mac.png +0 -0
  479. data/spec/support/static/git-scm.com/book/en/v2/images/github_win.png +0 -0
  480. data/spec/support/static/git-scm.com/book/en/v2/images/gitk.png +0 -0
  481. data/spec/support/static/git-scm.com/book/en/v2/images/gitlab-groups.png +0 -0
  482. data/spec/support/static/git-scm.com/book/en/v2/images/gitlab-menu.png +0 -0
  483. data/spec/support/static/git-scm.com/book/en/v2/images/gitlab-users.png +0 -0
  484. data/spec/support/static/git-scm.com/book/en/v2/images/head-to-master.png +0 -0
  485. data/spec/support/static/git-scm.com/book/en/v2/images/head-to-testing.png +0 -0
  486. data/spec/support/static/git-scm.com/book/en/v2/images/integration-manager.png +0 -0
  487. data/spec/support/static/git-scm.com/book/en/v2/images/interesting-rebase-1.png +0 -0
  488. data/spec/support/static/git-scm.com/book/en/v2/images/interesting-rebase-2.png +0 -0
  489. data/spec/support/static/git-scm.com/book/en/v2/images/interesting-rebase-3.png +0 -0
  490. data/spec/support/static/git-scm.com/book/en/v2/images/interesting-rebase-4.png +0 -0
  491. data/spec/support/static/git-scm.com/book/en/v2/images/interesting-rebase-5.png +0 -0
  492. data/spec/support/static/git-scm.com/book/en/v2/images/jb.png +0 -0
  493. data/spec/support/static/git-scm.com/book/en/v2/images/large-merges-1.png +0 -0
  494. data/spec/support/static/git-scm.com/book/en/v2/images/large-merges-2.png +0 -0
  495. data/spec/support/static/git-scm.com/book/en/v2/images/lifecycle.png +0 -0
  496. data/spec/support/static/git-scm.com/book/en/v2/images/local.png +0 -0
  497. data/spec/support/static/git-scm.com/book/en/v2/images/lr-branches-1.png +0 -0
  498. data/spec/support/static/git-scm.com/book/en/v2/images/lr-branches-2.png +0 -0
  499. data/spec/support/static/git-scm.com/book/en/v2/images/maint-01-email.png +0 -0
  500. data/spec/support/static/git-scm.com/book/en/v2/images/maint-02-merge.png +0 -0
  501. data/spec/support/static/git-scm.com/book/en/v2/images/maint-03-email-resp.png +0 -0
  502. data/spec/support/static/git-scm.com/book/en/v2/images/maint-04-target.png +0 -0
  503. data/spec/support/static/git-scm.com/book/en/v2/images/maint-05-mentions.png +0 -0
  504. data/spec/support/static/git-scm.com/book/en/v2/images/maint-06-unsubscribe.png +0 -0
  505. data/spec/support/static/git-scm.com/book/en/v2/images/maint-07-notifications.png +0 -0
  506. data/spec/support/static/git-scm.com/book/en/v2/images/maint-08-notifications-page.png +0 -0
  507. data/spec/support/static/git-scm.com/book/en/v2/images/maint-09-contrib.png +0 -0
  508. data/spec/support/static/git-scm.com/book/en/v2/images/maint-10-default-branch.png +0 -0
  509. data/spec/support/static/git-scm.com/book/en/v2/images/maint-11-transfer.png +0 -0
  510. data/spec/support/static/git-scm.com/book/en/v2/images/managed-team-1.png +0 -0
  511. data/spec/support/static/git-scm.com/book/en/v2/images/managed-team-2.png +0 -0
  512. data/spec/support/static/git-scm.com/book/en/v2/images/managed-team-3.png +0 -0
  513. data/spec/support/static/git-scm.com/book/en/v2/images/managed-team-flow.png +0 -0
  514. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-01-example.png +0 -0
  515. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-02-tasks.png +0 -0
  516. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-03-task-summary.png +0 -0
  517. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-04-fenced-code.png +0 -0
  518. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-05-quote.png +0 -0
  519. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-06-emoji-complete.png +0 -0
  520. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-07-emoji.png +0 -0
  521. data/spec/support/static/git-scm.com/book/en/v2/images/markdown-08-drag-drop.png +0 -0
  522. data/spec/support/static/git-scm.com/book/en/v2/images/mentions-01-syntax.png +0 -0
  523. data/spec/support/static/git-scm.com/book/en/v2/images/mentions-02-render.png +0 -0
  524. data/spec/support/static/git-scm.com/book/en/v2/images/mentions-03-closed.png +0 -0
  525. data/spec/support/static/git-scm.com/book/en/v2/images/merging-workflows-1.png +0 -0
  526. data/spec/support/static/git-scm.com/book/en/v2/images/merging-workflows-2.png +0 -0
  527. data/spec/support/static/git-scm.com/book/en/v2/images/merging-workflows-3.png +0 -0
  528. data/spec/support/static/git-scm.com/book/en/v2/images/merging-workflows-4.png +0 -0
  529. data/spec/support/static/git-scm.com/book/en/v2/images/merging-workflows-5.png +0 -0
  530. data/spec/support/static/git-scm.com/book/en/v2/images/new-repo.png +0 -0
  531. data/spec/support/static/git-scm.com/book/en/v2/images/neworg.png +0 -0
  532. data/spec/support/static/git-scm.com/book/en/v2/images/newrepo.png +0 -0
  533. data/spec/support/static/git-scm.com/book/en/v2/images/newrepoform.png +0 -0
  534. data/spec/support/static/git-scm.com/book/en/v2/images/orgs-01-page.png +0 -0
  535. data/spec/support/static/git-scm.com/book/en/v2/images/orgs-02-teams.png +0 -0
  536. data/spec/support/static/git-scm.com/book/en/v2/images/orgs-03-audit.png +0 -0
  537. data/spec/support/static/git-scm.com/book/en/v2/images/p4merge.png +0 -0
  538. data/spec/support/static/git-scm.com/book/en/v2/images/perils-of-rebasing-1.png +0 -0
  539. data/spec/support/static/git-scm.com/book/en/v2/images/perils-of-rebasing-2.png +0 -0
  540. data/spec/support/static/git-scm.com/book/en/v2/images/perils-of-rebasing-3.png +0 -0
  541. data/spec/support/static/git-scm.com/book/en/v2/images/perils-of-rebasing-4.png +0 -0
  542. data/spec/support/static/git-scm.com/book/en/v2/images/perils-of-rebasing-5.png +0 -0
  543. data/spec/support/static/git-scm.com/book/en/v2/images/posh-git.png +0 -0
  544. data/spec/support/static/git-scm.com/book/en/v2/images/pr-01-fail.png +0 -0
  545. data/spec/support/static/git-scm.com/book/en/v2/images/pr-02-merge-fix.png +0 -0
  546. data/spec/support/static/git-scm.com/book/en/v2/images/public-small-1.png +0 -0
  547. data/spec/support/static/git-scm.com/book/en/v2/images/public-small-2.png +0 -0
  548. data/spec/support/static/git-scm.com/book/en/v2/images/public-small-3.png +0 -0
  549. data/spec/support/static/git-scm.com/book/en/v2/images/rebasing-1.png +0 -0
  550. data/spec/support/static/git-scm.com/book/en/v2/images/rebasing-2.png +0 -0
  551. data/spec/support/static/git-scm.com/book/en/v2/images/remote-branches-1.png +0 -0
  552. data/spec/support/static/git-scm.com/book/en/v2/images/remote-branches-2.png +0 -0
  553. data/spec/support/static/git-scm.com/book/en/v2/images/remote-branches-3.png +0 -0
  554. data/spec/support/static/git-scm.com/book/en/v2/images/remote-branches-4.png +0 -0
  555. data/spec/support/static/git-scm.com/book/en/v2/images/remote-branches-5.png +0 -0
  556. data/spec/support/static/git-scm.com/book/en/v2/images/replace1.png +0 -0
  557. data/spec/support/static/git-scm.com/book/en/v2/images/replace2.png +0 -0
  558. data/spec/support/static/git-scm.com/book/en/v2/images/replace3.png +0 -0
  559. data/spec/support/static/git-scm.com/book/en/v2/images/replace4.png +0 -0
  560. data/spec/support/static/git-scm.com/book/en/v2/images/replace5.png +0 -0
  561. data/spec/support/static/git-scm.com/book/en/v2/images/reposettingslink.png +0 -0
  562. data/spec/support/static/git-scm.com/book/en/v2/images/rerere1.png +0 -0
  563. data/spec/support/static/git-scm.com/book/en/v2/images/rerere2.png +0 -0
  564. data/spec/support/static/git-scm.com/book/en/v2/images/rerere3.png +0 -0
  565. data/spec/support/static/git-scm.com/book/en/v2/images/reset-checkout.png +0 -0
  566. data/spec/support/static/git-scm.com/book/en/v2/images/reset-ex1.png +0 -0
  567. data/spec/support/static/git-scm.com/book/en/v2/images/reset-ex2.png +0 -0
  568. data/spec/support/static/git-scm.com/book/en/v2/images/reset-ex3.png +0 -0
  569. data/spec/support/static/git-scm.com/book/en/v2/images/reset-ex4.png +0 -0
  570. data/spec/support/static/git-scm.com/book/en/v2/images/reset-ex5.png +0 -0
  571. data/spec/support/static/git-scm.com/book/en/v2/images/reset-ex6.png +0 -0
  572. data/spec/support/static/git-scm.com/book/en/v2/images/reset-hard.png +0 -0
  573. data/spec/support/static/git-scm.com/book/en/v2/images/reset-mixed.png +0 -0
  574. data/spec/support/static/git-scm.com/book/en/v2/images/reset-path1.png +0 -0
  575. data/spec/support/static/git-scm.com/book/en/v2/images/reset-path2.png +0 -0
  576. data/spec/support/static/git-scm.com/book/en/v2/images/reset-path3.png +0 -0
  577. data/spec/support/static/git-scm.com/book/en/v2/images/reset-soft.png +0 -0
  578. data/spec/support/static/git-scm.com/book/en/v2/images/reset-squash-r1.png +0 -0
  579. data/spec/support/static/git-scm.com/book/en/v2/images/reset-squash-r2.png +0 -0
  580. data/spec/support/static/git-scm.com/book/en/v2/images/reset-squash-r3.png +0 -0
  581. data/spec/support/static/git-scm.com/book/en/v2/images/reset-start.png +0 -0
  582. data/spec/support/static/git-scm.com/book/en/v2/images/reset-workflow.png +0 -0
  583. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-01-services.png +0 -0
  584. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-02-email-service.png +0 -0
  585. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-03-webhook.png +0 -0
  586. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-04-webhook-debug.png +0 -0
  587. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-05-access-token.png +0 -0
  588. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-06-comment.png +0 -0
  589. data/spec/support/static/git-scm.com/book/en/v2/images/scripting-07-status.png +0 -0
  590. data/spec/support/static/git-scm.com/book/en/v2/images/signup.png +0 -0
  591. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-1.png +0 -0
  592. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-2.png +0 -0
  593. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-3.png +0 -0
  594. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-4.png +0 -0
  595. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-5.png +0 -0
  596. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-6.png +0 -0
  597. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-7.png +0 -0
  598. data/spec/support/static/git-scm.com/book/en/v2/images/small-team-flow.png +0 -0
  599. data/spec/support/static/git-scm.com/book/en/v2/images/smudge.png +0 -0
  600. data/spec/support/static/git-scm.com/book/en/v2/images/snapshots.png +0 -0
  601. data/spec/support/static/git-scm.com/book/en/v2/images/ssh-keys.png +0 -0
  602. data/spec/support/static/git-scm.com/book/en/v2/images/topic-branches-1.png +0 -0
  603. data/spec/support/static/git-scm.com/book/en/v2/images/topic-branches-2.png +0 -0
  604. data/spec/support/static/git-scm.com/book/en/v2/images/two-branches.png +0 -0
  605. data/spec/support/static/git-scm.com/book/en/v2/images/undomerge-reset.png +0 -0
  606. data/spec/support/static/git-scm.com/book/en/v2/images/undomerge-revert.png +0 -0
  607. data/spec/support/static/git-scm.com/book/en/v2/images/undomerge-revert2.png +0 -0
  608. data/spec/support/static/git-scm.com/book/en/v2/images/undomerge-revert3.png +0 -0
  609. data/spec/support/static/git-scm.com/book/en/v2/images/undomerge-start.png +0 -0
  610. data/spec/support/static/git-scm.com/book/en/v2/images/your-profile.png +0 -0
  611. data/spec/support/static/git-scm.com/book/en/v2/images/zsh-oh-my.png +0 -0
  612. data/spec/support/static/git-scm.com/book/en/v2/images/zsh-prompt.png +0 -0
  613. data/spec/support/static/git-scm.com/book/en/v2.html +688 -0
  614. data/spec/support/static/git-scm.com/favicon.ico +0 -0
  615. data/spec/support/static/git-scm.com/images/bg/body.jpg +0 -0
  616. data/spec/support/static/git-scm.com/images/bg/isometric-grid.png +0 -0
  617. data/spec/support/static/git-scm.com/images/bg/isometric-grid@2x.png +0 -0
  618. data/spec/support/static/git-scm.com/images/bg/search-header.jpg +0 -0
  619. data/spec/support/static/git-scm.com/images/company-project-logos/android.png +0 -0
  620. data/spec/support/static/git-scm.com/images/company-project-logos/android@2x.png +0 -0
  621. data/spec/support/static/git-scm.com/images/company-project-logos/eclipse.png +0 -0
  622. data/spec/support/static/git-scm.com/images/company-project-logos/eclipse@2x.png +0 -0
  623. data/spec/support/static/git-scm.com/images/company-project-logos/facebook.png +0 -0
  624. data/spec/support/static/git-scm.com/images/company-project-logos/facebook@2x.png +0 -0
  625. data/spec/support/static/git-scm.com/images/company-project-logos/gnome.png +0 -0
  626. data/spec/support/static/git-scm.com/images/company-project-logos/gnome@2x.png +0 -0
  627. data/spec/support/static/git-scm.com/images/company-project-logos/google.png +0 -0
  628. data/spec/support/static/git-scm.com/images/company-project-logos/google@2x.png +0 -0
  629. data/spec/support/static/git-scm.com/images/company-project-logos/kde.png +0 -0
  630. data/spec/support/static/git-scm.com/images/company-project-logos/kde@2x.png +0 -0
  631. data/spec/support/static/git-scm.com/images/company-project-logos/linked-in.png +0 -0
  632. data/spec/support/static/git-scm.com/images/company-project-logos/linked-in@2x.png +0 -0
  633. data/spec/support/static/git-scm.com/images/company-project-logos/linux.png +0 -0
  634. data/spec/support/static/git-scm.com/images/company-project-logos/linux@2x.png +0 -0
  635. data/spec/support/static/git-scm.com/images/company-project-logos/microsoft.png +0 -0
  636. data/spec/support/static/git-scm.com/images/company-project-logos/microsoft@2x.png +0 -0
  637. data/spec/support/static/git-scm.com/images/company-project-logos/netflix.png +0 -0
  638. data/spec/support/static/git-scm.com/images/company-project-logos/netflix@2x.png +0 -0
  639. data/spec/support/static/git-scm.com/images/company-project-logos/perl.png +0 -0
  640. data/spec/support/static/git-scm.com/images/company-project-logos/perl@2x.png +0 -0
  641. data/spec/support/static/git-scm.com/images/company-project-logos/postgresql.png +0 -0
  642. data/spec/support/static/git-scm.com/images/company-project-logos/postgresql@2x.png +0 -0
  643. data/spec/support/static/git-scm.com/images/company-project-logos/qt.png +0 -0
  644. data/spec/support/static/git-scm.com/images/company-project-logos/qt@2x.png +0 -0
  645. data/spec/support/static/git-scm.com/images/company-project-logos/rails.png +0 -0
  646. data/spec/support/static/git-scm.com/images/company-project-logos/rails@2x.png +0 -0
  647. data/spec/support/static/git-scm.com/images/company-project-logos/twitter.png +0 -0
  648. data/spec/support/static/git-scm.com/images/company-project-logos/twitter@2x.png +0 -0
  649. data/spec/support/static/git-scm.com/images/company-project-logos/x.png +0 -0
  650. data/spec/support/static/git-scm.com/images/company-project-logos/x@2x.png +0 -0
  651. data/spec/support/static/git-scm.com/images/epub.png +0 -0
  652. data/spec/support/static/git-scm.com/images/icons/admin-sm.png +0 -0
  653. data/spec/support/static/git-scm.com/images/icons/admin-sm@2x.png +0 -0
  654. data/spec/support/static/git-scm.com/images/icons/apple.png +0 -0
  655. data/spec/support/static/git-scm.com/images/icons/apple@2x.png +0 -0
  656. data/spec/support/static/git-scm.com/images/icons/book.png +0 -0
  657. data/spec/support/static/git-scm.com/images/icons/book@2x.png +0 -0
  658. data/spec/support/static/git-scm.com/images/icons/box.png +0 -0
  659. data/spec/support/static/git-scm.com/images/icons/box@2x.png +0 -0
  660. data/spec/support/static/git-scm.com/images/icons/branch-sm.png +0 -0
  661. data/spec/support/static/git-scm.com/images/icons/branch-sm@2x.png +0 -0
  662. data/spec/support/static/git-scm.com/images/icons/camera-sm.png +0 -0
  663. data/spec/support/static/git-scm.com/images/icons/camera-sm@2x.png +0 -0
  664. data/spec/support/static/git-scm.com/images/icons/chevron-up@2x.png +0 -0
  665. data/spec/support/static/git-scm.com/images/icons/code.png +0 -0
  666. data/spec/support/static/git-scm.com/images/icons/code@2x.png +0 -0
  667. data/spec/support/static/git-scm.com/images/icons/debugging-sm.png +0 -0
  668. data/spec/support/static/git-scm.com/images/icons/debugging-sm@2x.png +0 -0
  669. data/spec/support/static/git-scm.com/images/icons/document.png +0 -0
  670. data/spec/support/static/git-scm.com/images/icons/document@2x.png +0 -0
  671. data/spec/support/static/git-scm.com/images/icons/download.png +0 -0
  672. data/spec/support/static/git-scm.com/images/icons/email-sm.png +0 -0
  673. data/spec/support/static/git-scm.com/images/icons/email-sm@2x.png +0 -0
  674. data/spec/support/static/git-scm.com/images/icons/external-sm.png +0 -0
  675. data/spec/support/static/git-scm.com/images/icons/external-sm@2x.png +0 -0
  676. data/spec/support/static/git-scm.com/images/icons/gui.png +0 -0
  677. data/spec/support/static/git-scm.com/images/icons/gui@2x.png +0 -0
  678. data/spec/support/static/git-scm.com/images/icons/info.png +0 -0
  679. data/spec/support/static/git-scm.com/images/icons/info@2x.png +0 -0
  680. data/spec/support/static/git-scm.com/images/icons/inspection-sm.png +0 -0
  681. data/spec/support/static/git-scm.com/images/icons/inspection-sm@2x.png +0 -0
  682. data/spec/support/static/git-scm.com/images/icons/linux.png +0 -0
  683. data/spec/support/static/git-scm.com/images/icons/linux@2x.png +0 -0
  684. data/spec/support/static/git-scm.com/images/icons/nav-circles.png +0 -0
  685. data/spec/support/static/git-scm.com/images/icons/nav-circles@2x.png +0 -0
  686. data/spec/support/static/git-scm.com/images/icons/patching-sm.png +0 -0
  687. data/spec/support/static/git-scm.com/images/icons/patching-sm@2x.png +0 -0
  688. data/spec/support/static/git-scm.com/images/icons/plumbing-sm.png +0 -0
  689. data/spec/support/static/git-scm.com/images/icons/plumbing-sm@2x.png +0 -0
  690. data/spec/support/static/git-scm.com/images/icons/projects-sm.png +0 -0
  691. data/spec/support/static/git-scm.com/images/icons/projects-sm@2x.png +0 -0
  692. data/spec/support/static/git-scm.com/images/icons/search.png +0 -0
  693. data/spec/support/static/git-scm.com/images/icons/search@2x.png +0 -0
  694. data/spec/support/static/git-scm.com/images/icons/server-admin-sm.png +0 -0
  695. data/spec/support/static/git-scm.com/images/icons/server-admin-sm@2x.png +0 -0
  696. data/spec/support/static/git-scm.com/images/icons/setup-sm.png +0 -0
  697. data/spec/support/static/git-scm.com/images/icons/setup-sm@2x.png +0 -0
  698. data/spec/support/static/git-scm.com/images/icons/sharing-sm.png +0 -0
  699. data/spec/support/static/git-scm.com/images/icons/sharing-sm@2x.png +0 -0
  700. data/spec/support/static/git-scm.com/images/icons/sidebar.png +0 -0
  701. data/spec/support/static/git-scm.com/images/icons/sidebar@2x.png +0 -0
  702. data/spec/support/static/git-scm.com/images/icons/source-code.png +0 -0
  703. data/spec/support/static/git-scm.com/images/icons/source-code@2x.png +0 -0
  704. data/spec/support/static/git-scm.com/images/icons/windows.png +0 -0
  705. data/spec/support/static/git-scm.com/images/icons/windows@2x.png +0 -0
  706. data/spec/support/static/git-scm.com/images/logo@2x.png +0 -0
  707. data/spec/support/static/git-scm.com/images/mobi.png +0 -0
  708. data/spec/support/static/git-scm.com/images/monitor-default.png +0 -0
  709. data/spec/support/static/git-scm.com/images/monitor-default@2x.png +0 -0
  710. data/spec/support/static/git-scm.com/images/monitor-linux.png +0 -0
  711. data/spec/support/static/git-scm.com/images/monitor-linux@2x.png +0 -0
  712. data/spec/support/static/git-scm.com/images/monitor-mac.png +0 -0
  713. data/spec/support/static/git-scm.com/images/monitor-mac@2x.png +0 -0
  714. data/spec/support/static/git-scm.com/images/monitor-windows.png +0 -0
  715. data/spec/support/static/git-scm.com/images/monitor-windows@2x.png +0 -0
  716. data/spec/support/static/git-scm.com/images/pdf.png +0 -0
  717. data/spec/support/static/git-scm.com/images/progit2.png +0 -0
  718. data/spec/support/static/git-scm.com/images/sidebar-divider.png +0 -0
  719. data/spec/support/static/git-scm.com/images/sidebar-divider@2x.png +0 -0
  720. data/spec/support/static/git-scm.com/robots.txt +0 -0
  721. data/spec/task_spec.rb +7 -0
  722. data/spec/wayfarer_spec.rb +1 -1
  723. data/wayfarer.gemspec +9 -8
  724. metadata +692 -47
  725. data/docs/guides/browser_automation/capybara.md +0 -3
  726. data/lib/wayfarer/config.rb +0 -67
  727. data/lib/wayfarer/middleware/worker.rb +0 -47
  728. data/lib/wayfarer/networking/healer.rb +0 -21
  729. data/lib/wayfarer/networking/net_http.rb +0 -52
  730. data/lib/wayfarer/routing/custom_matcher.rb +0 -21
  731. data/lib/wayfarer/routing/host_matcher.rb +0 -23
  732. data/lib/wayfarer/routing/path_matcher.rb +0 -46
  733. data/lib/wayfarer/routing/query_matcher.rb +0 -67
  734. data/lib/wayfarer/routing/scheme_matcher.rb +0 -21
  735. data/lib/wayfarer/routing/suffix_matcher.rb +0 -21
  736. data/lib/wayfarer/routing/url_matcher.rb +0 -21
  737. data/spec/config_spec.rb +0 -144
  738. data/spec/factories/queue/chain.rb +0 -11
  739. data/spec/middleware/worker_spec.rb +0 -90
  740. data/spec/networking/adapter.rb +0 -135
  741. data/spec/networking/healer_spec.rb +0 -46
  742. data/spec/networking/net_http_spec.rb +0 -37
@@ -0,0 +1,2656 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <!-- Global site tag (gtag.js) - Google Analytics -->
6
+ <script async src="https://www.googletagmanager.com/gtag/js?id=UA-49925874-3"></script>
7
+ <script>
8
+ window.dataLayer = window.dataLayer || [];
9
+ function gtag(){dataLayer.push(arguments);}
10
+ gtag('js', new Date());
11
+
12
+ gtag('config', 'UA-49925874-3');
13
+ </script>
14
+
15
+ <meta charset='utf-8'>
16
+ <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'>
17
+ <meta name="viewport" content="width=device-width, initial-scale=1">
18
+ <title>Git - Git as a Client</title>
19
+
20
+ <link href='../../../favicon.ico' rel='shortcut icon' type='image/x-icon'>
21
+
22
+ <link rel="stylesheet" media="screen" href="../../../assets/application-cafcf280f67db0e6d8168ba98a38da878769a9d5f37793b68ffb963a02d185e0.css" />
23
+ <script src="../../../assets/modernize-b3ebe0c31c24f230dc62179d3e1030d2e57a53b1668d9382c0a27dbd44a94beb.js"></script>
24
+ <!--[if (gte IE 6)&(lte IE 8)]>
25
+ <script src="/javascripts/selectivizr-min.js"></script>
26
+ <![endif]-->
27
+
28
+ </head>
29
+
30
+ <body id="documentation">
31
+
32
+ <div class="inner">
33
+ <header>
34
+
35
+ <a href="https://git-scm.com/"><img src="../../../images/logo@2x.png" width="110" height="46" alt="Git" /></a>
36
+ <span id="tagline"></span>
37
+ <script type="text/javascript">
38
+ var taglines = ["fast-version-control","everything-is-local","distributed-even-if-your-workflow-isnt","local-branching-on-the-cheap","distributed-is-the-new-centralized"];
39
+ var tagline = taglines[Math.floor(Math.random() * taglines.length)];
40
+ document.getElementById('tagline').innerHTML = '--' + tagline;
41
+ </script>
42
+ <form id="search" action="https://git-scm.com/search/results">
43
+ <input id="search-text" name="search" placeholder="Search entire site..." autocomplete="off" type="text" />
44
+ </form>
45
+ <div id="search-results"></div>
46
+
47
+ </header>
48
+
49
+ </div> <!-- .inner -->
50
+
51
+ <div class="inner">
52
+ <div id="content-wrapper">
53
+ <button class="sidebar-btn"></button>
54
+ <aside class="sidebar" id="sidebar">
55
+ <nav>
56
+ <ul>
57
+ <li>
58
+ <a href="https://git-scm.com/about">About</a>
59
+ <ul class="">
60
+ <li>
61
+ <a href="https://git-scm.com/about">Branching and Merging</a>
62
+ </li>
63
+ <li>
64
+ <a href="https://git-scm.com/about/small-and-fast">Small and Fast</a>
65
+ </li>
66
+ <li>
67
+ <a href="https://git-scm.com/about/distributed">Distributed</a>
68
+ </li>
69
+ <li>
70
+ <a href="https://git-scm.com/about/info-assurance">Data Assurance</a>
71
+ </li>
72
+ <li>
73
+ <a href="https://git-scm.com/about/staging-area">Staging Area</a>
74
+ </li>
75
+ <li>
76
+ <a href="https://git-scm.com/about/free-and-open-source">Free and Open Source</a>
77
+ </li>
78
+ <li>
79
+ <a href="https://git-scm.com/about/trademark">Trademark</a>
80
+ </li>
81
+ </ul>
82
+ </li>
83
+ <li>
84
+ <a class="active" href="https://git-scm.com/doc">Documentation</a>
85
+ <ul class="expanded">
86
+ <li>
87
+ <a href="https://git-scm.com/docs">Reference</a>
88
+ </li>
89
+ <li>
90
+ <a class="active" href="https://git-scm.com/book">Book</a>
91
+ </li>
92
+ <li>
93
+ <a href="https://git-scm.com/videos">Videos</a>
94
+ </li>
95
+ <li>
96
+ <a href="https://git-scm.com/doc/ext">External Links</a>
97
+ </li>
98
+ </ul>
99
+ </li>
100
+ <li>
101
+ <a href="https://git-scm.com/downloads">Downloads</a>
102
+ <ul class="">
103
+ <li>
104
+ <a href="https://git-scm.com/downloads/guis">GUI Clients</a>
105
+ </li>
106
+ <li>
107
+ <a href="https://git-scm.com/downloads/logos">Logos</a>
108
+ </li>
109
+ </ul>
110
+ </li>
111
+ <li>
112
+ <a href="https://git-scm.com/community">Community</a>
113
+ </li>
114
+ </ul>
115
+ <hr class="sidebar">
116
+ <p>
117
+ This book is available in
118
+ <a href="https://git-scm.com/book/en">English</a>.
119
+ </p>
120
+ <p>
121
+ Full translation available in
122
+ <table>
123
+ <tr><td><a href="https://git-scm.com/book/az">azərbaycan dili</a>,</td></tr>
124
+ <tr><td><a href="https://git-scm.com/book/bg">български език</a>,</td></tr>
125
+ <tr><td><a href="https://git-scm.com/book/de">Deutsch</a>,</td></tr>
126
+ <tr><td><a href="https://git-scm.com/book/es">Español</a>,</td></tr>
127
+ <tr><td><a href="https://git-scm.com/book/fr">Français</a>,</td></tr>
128
+ <tr><td><a href="https://git-scm.com/book/gr">Ελληνικά</a>,</td></tr>
129
+ <tr><td><a href="https://git-scm.com/book/ja">日本語</a>,</td></tr>
130
+ <tr><td><a href="https://git-scm.com/book/ko">한국어</a>,</td></tr>
131
+ <tr><td><a href="https://git-scm.com/book/nl">Nederlands</a>,</td></tr>
132
+ <tr><td><a href="https://git-scm.com/book/ru">Русский</a>,</td></tr>
133
+ <tr><td><a href="https://git-scm.com/book/sl">Slovenščina</a>,</td></tr>
134
+ <tr><td><a href="https://git-scm.com/book/tl">Tagalog</a>,</td></tr>
135
+ <tr><td><a href="https://git-scm.com/book/uk">Українська</a></td></tr>
136
+ <tr><td><a href="https://git-scm.com/book/zh">简体中文</a>,</td></tr>
137
+ </table>
138
+ </p>
139
+ <p>
140
+ Partial translations available in
141
+ <table>
142
+ <tr><td><a href="https://git-scm.com/book/cs">Čeština</a>,</td></tr>
143
+ <tr><td><a href="https://git-scm.com/book/mk">Македонски</a>,</td></tr>
144
+ <tr><td><a href="https://git-scm.com/book/pl">Polski</a>,</td></tr>
145
+ <tr><td><a href="https://git-scm.com/book/sr">Српски</a>,</td></tr>
146
+ <tr><td><a href="https://git-scm.com/book/uz">Ўзбекча</a>,</td></tr>
147
+ <tr><td><a href="https://git-scm.com/book/zh-tw">繁體中文</a>,</td></tr>
148
+ </table>
149
+ </p>
150
+ <p>
151
+ Translations started for
152
+ <table>
153
+ <tr><td><a href="https://git-scm.com/book/be">Беларуская</a>,</td></tr>
154
+ <tr><td><a href="https://git-scm.com/book/fa" dir="rtl">فارسی</a>,</td></tr>
155
+ <tr><td><a href="https://git-scm.com/book/id">Indonesian</a>,</td></tr>
156
+ <tr><td><a href="https://git-scm.com/book/it">Italiano</a>,</td></tr>
157
+ <tr><td><a href="https://git-scm.com/book/ms">Bahasa Melayu</a>,</td></tr>
158
+ <tr><td><a href="https://git-scm.com/book/pt-br">Português (Brasil)</a>,</td></tr>
159
+ <tr><td><a href="https://git-scm.com/book/pt-pt">Português (Portugal)</a>,</td></tr>
160
+ <tr><td><a href="https://git-scm.com/book/sv">Svenska</a>,</td></tr>
161
+ <tr><td><a href="https://git-scm.com/book/tr">Türkçe</a>.</td></tr>
162
+ </table>
163
+ </p>
164
+ <hr class="sidebar"/>
165
+ <p>
166
+ The source of this book is <a href="https://github.com/progit/progit2">hosted on GitHub.</a></br>
167
+ Patches, suggestions and comments are welcome.
168
+ </p>
169
+
170
+
171
+ </nav>
172
+ </aside>
173
+
174
+ <div id="content">
175
+
176
+
177
+ <div id='book-chapters'>
178
+ <a class="dropdown-trigger" id="book-chapters-trigger" data-panel-id="chapters-dropdown" href="ch00/_git_svn.html#">Chapters ▾</a>
179
+ <div class='dropdown-panel' id='chapters-dropdown'>
180
+ <div class="three-column">
181
+ <div class='column-left'>
182
+ <ol class='book-toc'>
183
+ <li class='chapter'>
184
+ <h2>1. <a href="ch00/ch01-getting-started.html">Getting Started</a></h2>
185
+ <ol>
186
+ <li>
187
+ 1.1
188
+ <a href="ch00/ch01-getting-started.html" >About Version Control </a>
189
+ </li>
190
+ <li>
191
+ 1.2
192
+ <a href="Getting-Started-A-Short-History-of-Git.html" >A Short History of Git </a>
193
+ </li>
194
+ <li>
195
+ 1.3
196
+ <a href="ch00/what_is_git_section.html" >What is Git? </a>
197
+ </li>
198
+ <li>
199
+ 1.4
200
+ <a href="Getting-Started-The-Command-Line.html" >The Command Line </a>
201
+ </li>
202
+ <li>
203
+ 1.5
204
+ <a href="Getting-Started-Installing-Git.html" >Installing Git </a>
205
+ </li>
206
+ <li>
207
+ 1.6
208
+ <a href="ch00/_editor.html" >First-Time Git Setup </a>
209
+ </li>
210
+ <li>
211
+ 1.7
212
+ <a href="ch00/_git_help.html" >Getting Help </a>
213
+ </li>
214
+ <li>
215
+ 1.8
216
+ <a href="Getting-Started-Summary.html" >Summary </a>
217
+ </li>
218
+ </ol>
219
+ </li>
220
+ <li class='chapter'>
221
+ <h2>2. <a href="ch00/_git_cloning.html">Git Basics</a></h2>
222
+ <ol>
223
+ <li>
224
+ 2.1
225
+ <a href="ch00/_git_cloning.html" >Getting a Git Repository </a>
226
+ </li>
227
+ <li>
228
+ 2.2
229
+ <a href="ch00/_git_mv.html" >Recording Changes to the Repository </a>
230
+ </li>
231
+ <li>
232
+ 2.3
233
+ <a href="ch00/_viewing_history.html" >Viewing the Commit History </a>
234
+ </li>
235
+ <li>
236
+ 2.4
237
+ <a href="ch00/_unstaging.html" >Undoing Things </a>
238
+ </li>
239
+ <li>
240
+ 2.5
241
+ <a href="ch00/_remote_repos.html" >Working with Remotes </a>
242
+ </li>
243
+ <li>
244
+ 2.6
245
+ <a href="ch00/_annotated_tags.html" >Tagging </a>
246
+ </li>
247
+ <li>
248
+ 2.7
249
+ <a href="ch00/_git_aliases.html" >Git Aliases </a>
250
+ </li>
251
+ <li>
252
+ 2.8
253
+ <a href="Git-Basics-Summary.html" >Summary </a>
254
+ </li>
255
+ </ol>
256
+ </li>
257
+ <li class='chapter'>
258
+ <h2>3. <a href="ch00/_switching_branches.html">Git Branching</a></h2>
259
+ <ol>
260
+ <li>
261
+ 3.1
262
+ <a href="ch00/_switching_branches.html" >Branches in a Nutshell </a>
263
+ </li>
264
+ <li>
265
+ 3.2
266
+ <a href="ch00/_basic_branching.html" >Basic Branching and Merging </a>
267
+ </li>
268
+ <li>
269
+ 3.3
270
+ <a href="ch00/_branch_management.html" >Branch Management </a>
271
+ </li>
272
+ <li>
273
+ 3.4
274
+ <a href="ch00/_topic_branch.html" >Branching Workflows </a>
275
+ </li>
276
+ <li>
277
+ 3.5
278
+ <a href="ch00/_delete_branches.html" >Remote Branches </a>
279
+ </li>
280
+ <li>
281
+ 3.6
282
+ <a href="ch00/_rebase_rebase.html" >Rebasing </a>
283
+ </li>
284
+ <li>
285
+ 3.7
286
+ <a href="Git-Branching-Summary.html" >Summary </a>
287
+ </li>
288
+ </ol>
289
+ </li>
290
+ <li class='chapter'>
291
+ <h2>4. <a href="Git-on-the-Server-The-Protocols.html">Git on the Server</a></h2>
292
+ <ol>
293
+ <li>
294
+ 4.1
295
+ <a href="Git-on-the-Server-The-Protocols.html" >The Protocols </a>
296
+ </li>
297
+ <li>
298
+ 4.2
299
+ <a href="ch00/_bare_repo.html" >Getting Git on a Server </a>
300
+ </li>
301
+ <li>
302
+ 4.3
303
+ <a href="ch00/_generate_ssh_key.html" >Generating Your SSH Public Key </a>
304
+ </li>
305
+ <li>
306
+ 4.4
307
+ <a href="ch00/_setting_up_server.html" >Setting Up the Server </a>
308
+ </li>
309
+ <li>
310
+ 4.5
311
+ <a href="Git-on-the-Server-Git-Daemon.html" >Git Daemon </a>
312
+ </li>
313
+ <li>
314
+ 4.6
315
+ <a href="Git-on-the-Server-Smart-HTTP.html" >Smart HTTP </a>
316
+ </li>
317
+ <li>
318
+ 4.7
319
+ <a href="Git-on-the-Server-GitWeb.html" >GitWeb </a>
320
+ </li>
321
+ <li>
322
+ 4.8
323
+ <a href="ch00/_gitlab_groups_section.html" >GitLab </a>
324
+ </li>
325
+ <li>
326
+ 4.9
327
+ <a href="Git-on-the-Server-Third-Party-Hosted-Options.html" >Third Party Hosted Options </a>
328
+ </li>
329
+ <li>
330
+ 4.10
331
+ <a href="Git-on-the-Server-Summary.html" >Summary </a>
332
+ </li>
333
+ </ol>
334
+ </li>
335
+ <li class='chapter'>
336
+ <h2>5. <a href="ch00/_integration_manager.html">Distributed Git</a></h2>
337
+ <ol>
338
+ <li>
339
+ 5.1
340
+ <a href="ch00/_integration_manager.html" >Distributed Workflows </a>
341
+ </li>
342
+ <li>
343
+ 5.2
344
+ <a href="ch00/_project_over_email.html" >Contributing to a Project </a>
345
+ </li>
346
+ <li>
347
+ 5.3
348
+ <a href="ch00/_git_am.html" >Maintaining a Project </a>
349
+ </li>
350
+ <li>
351
+ 5.4
352
+ <a href="Distributed-Git-Summary.html" >Summary </a>
353
+ </li>
354
+ </ol>
355
+ </li>
356
+ </ol>
357
+
358
+ </div>
359
+ <div class='column-middle'>
360
+ <ol class='book-toc'>
361
+ <li class='chapter'>
362
+ <h2>6. <a href="ch00/_personal_avatar.html">GitHub</a></h2>
363
+ <ol>
364
+ <li>
365
+ 6.1
366
+ <a href="ch00/_personal_avatar.html" >Account Setup and Configuration </a>
367
+ </li>
368
+ <li>
369
+ 6.2
370
+ <a href="ch00/_fetch_and_push_on_different_repositories.html" >Contributing to a Project </a>
371
+ </li>
372
+ <li>
373
+ 6.3
374
+ <a href="ch00/_email_notifications.html" >Maintaining a Project </a>
375
+ </li>
376
+ <li>
377
+ 6.4
378
+ <a href="ch00/_team_page.html" >Managing an organization </a>
379
+ </li>
380
+ <li>
381
+ 6.5
382
+ <a href="ch00/_commit_status.html" >Scripting GitHub </a>
383
+ </li>
384
+ <li>
385
+ 6.6
386
+ <a href="GitHub-Summary.html" >Summary </a>
387
+ </li>
388
+ </ol>
389
+ </li>
390
+ <li class='chapter'>
391
+ <h2>7. <a href="ch00/_git_reflog.html">Git Tools</a></h2>
392
+ <ol>
393
+ <li>
394
+ 7.1
395
+ <a href="ch00/_git_reflog.html" >Revision Selection </a>
396
+ </li>
397
+ <li>
398
+ 7.2
399
+ <a href="ch00/_interactive_staging.html" >Interactive Staging </a>
400
+ </li>
401
+ <li>
402
+ 7.3
403
+ <a href="ch00/_git_clean.html" >Stashing and Cleaning </a>
404
+ </li>
405
+ <li>
406
+ 7.4
407
+ <a href="ch00/_signing_commits.html" >Signing Your Work </a>
408
+ </li>
409
+ <li>
410
+ 7.5
411
+ <a href="ch00/_git_grep.html" >Searching </a>
412
+ </li>
413
+ <li>
414
+ 7.6
415
+ <a href="ch00/_removing_file_every_commit.html" >Rewriting History </a>
416
+ </li>
417
+ <li>
418
+ 7.7
419
+ <a href="ch00/_the_index.html" >Reset Demystified </a>
420
+ </li>
421
+ <li>
422
+ 7.8
423
+ <a href="ch00/_reverse_commit.html" >Advanced Merging </a>
424
+ </li>
425
+ <li>
426
+ 7.9
427
+ <a href="ch00/ref_rerere.html" >Rerere </a>
428
+ </li>
429
+ <li>
430
+ 7.10
431
+ <a href="ch00/_file_annotation.html" >Debugging with Git </a>
432
+ </li>
433
+ <li>
434
+ 7.11
435
+ <a href="ch00/_publishing_submodules.html" >Submodules </a>
436
+ </li>
437
+ <li>
438
+ 7.12
439
+ <a href="ch00/_bundling.html" >Bundling </a>
440
+ </li>
441
+ <li>
442
+ 7.13
443
+ <a href="ch00/_replace.html" >Replace </a>
444
+ </li>
445
+ <li>
446
+ 7.14
447
+ <a href="ch00/_credential_caching.html" >Credential Storage </a>
448
+ </li>
449
+ <li>
450
+ 7.15
451
+ <a href="Git-Tools-Summary.html" >Summary </a>
452
+ </li>
453
+ </ol>
454
+ </li>
455
+ <li class='chapter'>
456
+ <h2>8. <a href="ch00/_external_merge_tools.html">Customizing Git</a></h2>
457
+ <ol>
458
+ <li>
459
+ 8.1
460
+ <a href="ch00/_external_merge_tools.html" >Git Configuration </a>
461
+ </li>
462
+ <li>
463
+ 8.2
464
+ <a href="ch00/_keyword_expansion.html" >Git Attributes </a>
465
+ </li>
466
+ <li>
467
+ 8.3
468
+ <a href="ch00/_email_hooks.html" >Git Hooks </a>
469
+ </li>
470
+ <li>
471
+ 8.4
472
+ <a href="ch00/_enforcing_commit_message_format.html" >An Example Git-Enforced Policy </a>
473
+ </li>
474
+ <li>
475
+ 8.5
476
+ <a href="Customizing-Git-Summary.html" >Summary </a>
477
+ </li>
478
+ </ol>
479
+ </li>
480
+ <li class='chapter'>
481
+ <h2>9. <a href="ch00/_git_svn.html">Git and Other Systems</a></h2>
482
+ <ol>
483
+ <li>
484
+ 9.1
485
+ <a href="ch00/_git_svn.html" class=active>Git as a Client </a>
486
+ </li>
487
+ <li>
488
+ 9.2
489
+ <a href="ch00/_git_p4.html" >Migrating to Git </a>
490
+ </li>
491
+ <li>
492
+ 9.3
493
+ <a href="Git-and-Other-Systems-Summary.html" >Summary </a>
494
+ </li>
495
+ </ol>
496
+ </li>
497
+ <li class='chapter'>
498
+ <h2>10. <a href="ch00/_plumbing_porcelain.html">Git Internals</a></h2>
499
+ <ol>
500
+ <li>
501
+ 10.1
502
+ <a href="ch00/_plumbing_porcelain.html" >Plumbing and Porcelain </a>
503
+ </li>
504
+ <li>
505
+ 10.2
506
+ <a href="ch00/_git_commit_objects.html" >Git Objects </a>
507
+ </li>
508
+ <li>
509
+ 10.3
510
+ <a href="ch00/ref_the_ref.html" >Git References </a>
511
+ </li>
512
+ <li>
513
+ 10.4
514
+ <a href="Git-Internals-Packfiles.html" >Packfiles </a>
515
+ </li>
516
+ <li>
517
+ 10.5
518
+ <a href="ch00/_pushing_refspecs.html" >The Refspec </a>
519
+ </li>
520
+ <li>
521
+ 10.6
522
+ <a href="Git-Internals-Transfer-Protocols.html" >Transfer Protocols </a>
523
+ </li>
524
+ <li>
525
+ 10.7
526
+ <a href="ch00/_git_gc.html" >Maintenance and Data Recovery </a>
527
+ </li>
528
+ <li>
529
+ 10.8
530
+ <a href="Git-Internals-Environment-Variables.html" >Environment Variables </a>
531
+ </li>
532
+ <li>
533
+ 10.9
534
+ <a href="Git-Internals-Summary.html" >Summary </a>
535
+ </li>
536
+ </ol>
537
+ </li>
538
+ </ol>
539
+
540
+ </div>
541
+ <div class='column-right'>
542
+ <ol class='book-toc'>
543
+ <li class='chapter'>
544
+ <h2>A1. <a href="./Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces.html">Appendix A: Git in Other Environments</a></h2>
545
+ <ol>
546
+ <li>
547
+ A1.1
548
+ <a href="./Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces.html" >Graphical Interfaces </a>
549
+ </li>
550
+ <li>
551
+ A1.2
552
+ <a href="./Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio.html" >Git in Visual Studio </a>
553
+ </li>
554
+ <li>
555
+ A1.3
556
+ <a href="./Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio-Code.html" >Git in Visual Studio Code </a>
557
+ </li>
558
+ <li>
559
+ A1.4
560
+ <a href="./Appendix-A:-Git-in-Other-Environments-Git-in-IntelliJ-%252F-PyCharm-%252F-WebStorm-%252F-PhpStorm-%252F-RubyMine.html" >Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine </a>
561
+ </li>
562
+ <li>
563
+ A1.5
564
+ <a href="./Appendix-A:-Git-in-Other-Environments-Git-in-Sublime-Text.html" >Git in Sublime Text </a>
565
+ </li>
566
+ <li>
567
+ A1.6
568
+ <a href="./Appendix-A:-Git-in-Other-Environments-Git-in-Bash.html" >Git in Bash </a>
569
+ </li>
570
+ <li>
571
+ A1.7
572
+ <a href="ch00/oh_my_zsh_git.html" >Git in Zsh </a>
573
+ </li>
574
+ <li>
575
+ A1.8
576
+ <a href="./Appendix-A:-Git-in-Other-Environments-Git-in-PowerShell.html" >Git in PowerShell </a>
577
+ </li>
578
+ <li>
579
+ A1.9
580
+ <a href="./Appendix-A:-Git-in-Other-Environments-Summary.html" >Summary </a>
581
+ </li>
582
+ </ol>
583
+ </li>
584
+ <li class='chapter'>
585
+ <h2>A2. <a href="./Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git.html">Appendix B: Embedding Git in your Applications</a></h2>
586
+ <ol>
587
+ <li>
588
+ A2.1
589
+ <a href="./Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git.html" >Command-line Git </a>
590
+ </li>
591
+ <li>
592
+ A2.2
593
+ <a href="ch00/_libgit2_bindings.html" >Libgit2 </a>
594
+ </li>
595
+ <li>
596
+ A2.3
597
+ <a href="./Appendix-B:-Embedding-Git-in-your-Applications-JGit.html" >JGit </a>
598
+ </li>
599
+ <li>
600
+ A2.4
601
+ <a href="./Appendix-B:-Embedding-Git-in-your-Applications-go-git.html" >go-git </a>
602
+ </li>
603
+ <li>
604
+ A2.5
605
+ <a href="./Appendix-B:-Embedding-Git-in-your-Applications-Dulwich.html" >Dulwich </a>
606
+ </li>
607
+ </ol>
608
+ </li>
609
+ <li class='chapter'>
610
+ <h2>A3. <a href="ch00/ch_core_editor.html">Appendix C: Git Commands</a></h2>
611
+ <ol>
612
+ <li>
613
+ A3.1
614
+ <a href="ch00/ch_core_editor.html" >Setup and Config </a>
615
+ </li>
616
+ <li>
617
+ A3.2
618
+ <a href="./Appendix-C:-Git-Commands-Getting-and-Creating-Projects.html" >Getting and Creating Projects </a>
619
+ </li>
620
+ <li>
621
+ A3.3
622
+ <a href="./Appendix-C:-Git-Commands-Basic-Snapshotting.html" >Basic Snapshotting </a>
623
+ </li>
624
+ <li>
625
+ A3.4
626
+ <a href="./Appendix-C:-Git-Commands-Branching-and-Merging.html" >Branching and Merging </a>
627
+ </li>
628
+ <li>
629
+ A3.5
630
+ <a href="./Appendix-C:-Git-Commands-Sharing-and-Updating-Projects.html" >Sharing and Updating Projects </a>
631
+ </li>
632
+ <li>
633
+ A3.6
634
+ <a href="./Appendix-C:-Git-Commands-Inspection-and-Comparison.html" >Inspection and Comparison </a>
635
+ </li>
636
+ <li>
637
+ A3.7
638
+ <a href="./Appendix-C:-Git-Commands-Debugging.html" >Debugging </a>
639
+ </li>
640
+ <li>
641
+ A3.8
642
+ <a href="./Appendix-C:-Git-Commands-Patching.html" >Patching </a>
643
+ </li>
644
+ <li>
645
+ A3.9
646
+ <a href="./Appendix-C:-Git-Commands-Email.html" >Email </a>
647
+ </li>
648
+ <li>
649
+ A3.10
650
+ <a href="./Appendix-C:-Git-Commands-External-Systems.html" >External Systems </a>
651
+ </li>
652
+ <li>
653
+ A3.11
654
+ <a href="./Appendix-C:-Git-Commands-Administration.html" >Administration </a>
655
+ </li>
656
+ <li>
657
+ A3.12
658
+ <a href="./Appendix-C:-Git-Commands-Plumbing-Commands.html" >Plumbing Commands </a>
659
+ </li>
660
+ </ol>
661
+ </li>
662
+ </ol>
663
+
664
+ </div>
665
+ </div>
666
+ </div>
667
+
668
+ <span class="light" id="edition">
669
+ 2nd Edition
670
+ </span>
671
+ </div>
672
+
673
+ <div id='main' class="book edition2">
674
+ <h1>9.1 Git and Other Systems - Git as a Client</h1>
675
+ <div><p>The world isn’t perfect.
676
+ Usually, you can’t immediately switch every project you come in contact with to Git.
677
+ Sometimes you’re stuck on a project using another VCS, and wish it was Git.
678
+ We’ll spend the first part of this chapter learning about ways to use Git as a client when the project you’re working on is hosted in a different system.</p><p>At some point, you may want to convert your existing project to Git.
679
+ The second part of this chapter covers how to migrate your project into Git from several specific systems, as well as a method that will work if no pre-built import tool exists.</p>
680
+ <h2 id="_git_as_a_client">Git as a Client</h2>
681
+ <div class="paragraph">
682
+ <p>
683
+ Git provides such a nice experience for developers that many people have figured out how to use it on their workstation, even if the rest of their team is using an entirely different VCS.
684
+ There are a number of these adapters, called “bridges,” available.
685
+ Here we’ll cover the ones you’re most likely to run into in the wild.</p>
686
+ </div>
687
+ <div class="sect3">
688
+ <h3 id="_git_svn">Git and Subversion</h3>
689
+ <div class="paragraph">
690
+ <p>
691
+ A large fraction of open source development projects and a good number of corporate projects use Subversion to manage their source code.
692
+ It’s been around for more than a decade, and for most of that time was the <em>de facto</em> VCS choice for open-source projects.
693
+ It’s also very similar in many ways to CVS, which was the big boy of the source-control world before that.</p>
694
+ </div>
695
+ <div class="paragraph">
696
+ <p>
697
+ One of Git’s great features is a bidirectional bridge to Subversion called <code>git svn</code>.
698
+ This tool allows you to use Git as a valid client to a Subversion server, so you can use all the local features of Git and then push to a Subversion server as if you were using Subversion locally.
699
+ This means you can do local branching and merging, use the staging area, use rebasing and cherry-picking, and so on, while your collaborators continue to work in their dark and ancient ways.
700
+ It’s a good way to sneak Git into the corporate environment and help your fellow developers become more efficient while you lobby to get the infrastructure changed to support Git fully.
701
+ The Subversion bridge is the gateway drug to the DVCS world.</p>
702
+ </div>
703
+ <div class="sect4">
704
+ <h4 id="_git_svn_2"><code>git svn</code></h4>
705
+ <div class="paragraph">
706
+ <p>The base command in Git for all the Subversion bridging commands is <code>git svn</code>.
707
+ It takes quite a few commands, so we’ll show the most common while going through a few simple workflows.</p>
708
+ </div>
709
+ <div class="paragraph">
710
+ <p>It’s important to note that when you’re using <code>git svn</code>, you’re interacting with Subversion, which is a system that works very differently from Git.
711
+ Although you <strong>can</strong> do local branching and merging, it’s generally best to keep your history as linear as possible by rebasing your work, and avoiding doing things like simultaneously interacting with a Git remote repository.</p>
712
+ </div>
713
+ <div class="paragraph">
714
+ <p>Don’t rewrite your history and try to push again, and don’t push to a parallel Git repository to collaborate with fellow Git developers at the same time.
715
+ Subversion can have only a single linear history, and confusing it is very easy.
716
+ If you’re working with a team, and some are using SVN and others are using Git, make sure everyone is using the SVN server to collaborate – doing so will make your life easier.</p>
717
+ </div>
718
+ </div>
719
+ <div class="sect4">
720
+ <h4 id="_setting_up">Setting Up</h4>
721
+ <div class="paragraph">
722
+ <p>To demonstrate this functionality, you need a typical SVN repository that you have write access to.
723
+ If you want to copy these examples, you’ll have to make a writeable copy of an SVN test repository.
724
+ In order to do that easily, you can use a tool called <code>svnsync</code> that comes with Subversion.</p>
725
+ </div>
726
+ <div class="paragraph">
727
+ <p>To follow along, you first need to create a new local Subversion repository:</p>
728
+ </div>
729
+ <div class="listingblock">
730
+ <div class="content">
731
+ <pre class="highlight"><code class="language-console" data-lang="console">$ mkdir /tmp/test-svn
732
+ $ svnadmin create /tmp/test-svn</code></pre>
733
+ </div>
734
+ </div>
735
+ <div class="paragraph">
736
+ <p>Then, enable all users to change revprops – the easy way is to add a <code>pre-revprop-change</code> script that always exits 0:</p>
737
+ </div>
738
+ <div class="listingblock">
739
+ <div class="content">
740
+ <pre class="highlight"><code class="language-console" data-lang="console">$ cat /tmp/test-svn/hooks/pre-revprop-change
741
+ #!/bin/sh
742
+ exit 0;
743
+ $ chmod +x /tmp/test-svn/hooks/pre-revprop-change</code></pre>
744
+ </div>
745
+ </div>
746
+ <div class="paragraph">
747
+ <p>You can now sync this project to your local machine by calling <code>svnsync init</code> with the to and from repositories.</p>
748
+ </div>
749
+ <div class="listingblock">
750
+ <div class="content">
751
+ <pre class="highlight"><code class="language-console" data-lang="console">$ svnsync init file:///tmp/test-svn \
752
+ http://your-svn-server.example.org/svn/</code></pre>
753
+ </div>
754
+ </div>
755
+ <div class="paragraph">
756
+ <p>This sets up the properties to run the sync.
757
+ You can then clone the code by running:</p>
758
+ </div>
759
+ <div class="listingblock">
760
+ <div class="content">
761
+ <pre class="highlight"><code class="language-console" data-lang="console">$ svnsync sync file:///tmp/test-svn
762
+ Committed revision 1.
763
+ Copied properties for revision 1.
764
+ Transmitting file data .............................[...]
765
+ Committed revision 2.
766
+ Copied properties for revision 2.
767
+ […]</code></pre>
768
+ </div>
769
+ </div>
770
+ <div class="paragraph">
771
+ <p>Although this operation may take only a few minutes, if you try to copy the original repository to another remote repository instead of a local one, the process will take nearly an hour, even though there are fewer than 100 commits.
772
+ Subversion has to clone one revision at a time and then push it back into another repository – it’s ridiculously inefficient, but it’s the only easy way to do this.</p>
773
+ </div>
774
+ </div>
775
+ <div class="sect4">
776
+ <h4 id="_getting_started">Getting Started</h4>
777
+ <div class="paragraph">
778
+ <p>Now that you have a Subversion repository to which you have write access, you can go through a typical workflow.
779
+ You’ll start with the <code>git svn clone</code> command, which imports an entire Subversion repository into a local Git repository.
780
+ Remember that if you’re importing from a real hosted Subversion repository, you should replace the <code>file:///tmp/test-svn</code> here with the URL of your Subversion repository:</p>
781
+ </div>
782
+ <div class="listingblock">
783
+ <div class="content">
784
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
785
+ Initialized empty Git repository in /private/tmp/progit/test-svn/.git/
786
+ r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk)
787
+ A m4/acx_pthread.m4
788
+ A m4/stl_hash.m4
789
+ A java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
790
+ A java/src/test/java/com/google/protobuf/WireFormatTest.java
791
+
792
+ r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk)
793
+ Found possible branch point: file:///tmp/test-svn/trunk =&gt; file:///tmp/test-svn/branches/my-calc-branch, 75
794
+ Found branch parent: (refs/remotes/origin/my-calc-branch) 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae
795
+ Following parent with do_switch
796
+ Successfully followed parent
797
+ r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-calc-branch)
798
+ Checked out HEAD:
799
+ file:///tmp/test-svn/trunk r75</code></pre>
800
+ </div>
801
+ </div>
802
+ <div class="paragraph">
803
+ <p>This runs the equivalent of two commands – <code>git svn init</code> followed by <code>git svn fetch</code> – on the URL you provide.
804
+ This can take a while.
805
+ If, for example, the test project has only about 75 commits and the codebase isn’t that big, Git nevertheless must check out each version, one at a time, and commit it individually.
806
+ For a project with hundreds or thousands of commits, this can literally take hours or even days to finish.</p>
807
+ </div>
808
+ <div class="paragraph">
809
+ <p>The <code>-T trunk -b branches -t tags</code> part tells Git that this Subversion repository follows the basic branching and tagging conventions.
810
+ If you name your trunk, branches, or tags differently, you can change these options.
811
+ Because this is so common, you can replace this entire part with <code>-s</code>, which means standard layout and implies all those options.
812
+ The following command is equivalent:</p>
813
+ </div>
814
+ <div class="listingblock">
815
+ <div class="content">
816
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn clone file:///tmp/test-svn -s</code></pre>
817
+ </div>
818
+ </div>
819
+ <div class="paragraph">
820
+ <p>At this point, you should have a valid Git repository that has imported your branches and tags:</p>
821
+ </div>
822
+ <div class="listingblock">
823
+ <div class="content">
824
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git branch -a
825
+ * master
826
+ remotes/origin/my-calc-branch
827
+ remotes/origin/tags/2.0.2
828
+ remotes/origin/tags/release-2.0.1
829
+ remotes/origin/tags/release-2.0.2
830
+ remotes/origin/tags/release-2.0.2rc1
831
+ remotes/origin/trunk</code></pre>
832
+ </div>
833
+ </div>
834
+ <div class="paragraph">
835
+ <p>Note how this tool manages Subversion tags as remote refs.
836
+
837
+ Let’s take a closer look with the Git plumbing command <code>show-ref</code>:</p>
838
+ </div>
839
+ <div class="listingblock">
840
+ <div class="content">
841
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git show-ref
842
+ 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master
843
+ 0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-branch
844
+ bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2
845
+ 285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-2.0.1
846
+ cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-2.0.2
847
+ a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-2.0.2rc1
848
+ 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk</code></pre>
849
+ </div>
850
+ </div>
851
+ <div class="paragraph">
852
+ <p>Git doesn’t do this when it clones from a Git server; here’s what a repository with tags looks like after a fresh clone:</p>
853
+ </div>
854
+ <div class="listingblock">
855
+ <div class="content">
856
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git show-ref
857
+ c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master
858
+ 32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1
859
+ 75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2
860
+ 23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0
861
+ 7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0
862
+ 6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0</code></pre>
863
+ </div>
864
+ </div>
865
+ <div class="paragraph">
866
+ <p>Git fetches the tags directly into <code>refs/tags</code>, rather than treating them remote branches.</p>
867
+ </div>
868
+ </div>
869
+ <div class="sect4">
870
+ <h4 id="_committing_back_to_subversion">Committing Back to Subversion</h4>
871
+ <div class="paragraph">
872
+ <p>Now that you have a working directory, you can do some work on the project and push your commits back upstream, using Git effectively as an SVN client.
873
+ If you edit one of the files and commit it, you have a commit that exists in Git locally that doesn’t exist on the Subversion server:</p>
874
+ </div>
875
+ <div class="listingblock">
876
+ <div class="content">
877
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git commit -am 'Adding git-svn instructions to the README'
878
+ [master 4af61fd] Adding git-svn instructions to the README
879
+ 1 file changed, 5 insertions(+)</code></pre>
880
+ </div>
881
+ </div>
882
+ <div class="paragraph">
883
+ <p>Next, you need to push your change upstream.
884
+ Notice how this changes the way you work with Subversion – you can do several commits offline and then push them all at once to the Subversion server.
885
+ To push to a Subversion server, you run the <code>git svn dcommit</code> command:</p>
886
+ </div>
887
+ <div class="listingblock">
888
+ <div class="content">
889
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit
890
+ Committing to file:///tmp/test-svn/trunk ...
891
+ M README.txt
892
+ Committed r77
893
+ M README.txt
894
+ r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk)
895
+ No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and refs/remotes/origin/trunk
896
+ Resetting to the latest refs/remotes/origin/trunk</code></pre>
897
+ </div>
898
+ </div>
899
+ <div class="paragraph">
900
+ <p>This takes all the commits you’ve made on top of the Subversion server code, does a Subversion commit for each, and then rewrites your local Git commit to include a unique identifier.
901
+ This is important because it means that all the SHA-1 checksums for your commits change.
902
+ Partly for this reason, working with Git-based remote versions of your projects concurrently with a Subversion server isn’t a good idea.
903
+ If you look at the last commit, you can see the new <code>git-svn-id</code> that was added:</p>
904
+ </div>
905
+ <div class="listingblock">
906
+ <div class="content">
907
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git log -1
908
+ commit 95e0222ba6399739834380eb10afcd73e0670bc5
909
+ Author: ben &lt;ben@0b684db3-b064-4277-89d1-21af03df0a68&gt;
910
+ Date: Thu Jul 24 03:08:36 2014 +0000
911
+
912
+ Adding git-svn instructions to the README
913
+
914
+ git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-21af03df0a68</code></pre>
915
+ </div>
916
+ </div>
917
+ <div class="paragraph">
918
+ <p>Notice that the SHA-1 checksum that originally started with <code>4af61fd</code> when you committed now begins with <code>95e0222</code>.
919
+ If you want to push to both a Git server and a Subversion server, you have to push (<code>dcommit</code>) to the Subversion server first, because that action changes your commit data.</p>
920
+ </div>
921
+ </div>
922
+ <div class="sect4">
923
+ <h4 id="_pulling_in_new_changes">Pulling in New Changes</h4>
924
+ <div class="paragraph">
925
+ <p>If you’re working with other developers, then at some point one of you will push, and then the other one will try to push a change that conflicts.
926
+ That change will be rejected until you merge in their work.
927
+ In <code>git svn</code>, it looks like this:</p>
928
+ </div>
929
+ <div class="listingblock">
930
+ <div class="content">
931
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit
932
+ Committing to file:///tmp/test-svn/trunk ...
933
+
934
+ ERROR from SVN:
935
+ Transaction is out of date: File '/trunk/README.txt' is out of date
936
+ W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk differ, using rebase:
937
+ :100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145 c80b6127dd04f5fcda218730ddf3a2da4eb39138 M README.txt
938
+ Current branch master is up to date.
939
+ ERROR: Not all changes have been committed into SVN, however the committed
940
+ ones (if any) seem to be successfully integrated into the working tree.
941
+ Please see the above messages for details.</code></pre>
942
+ </div>
943
+ </div>
944
+ <div class="paragraph">
945
+ <p>To resolve this situation, you can run <code>git svn rebase</code>, which pulls down any changes on the server that you don’t have yet and rebases any work you have on top of what is on the server:</p>
946
+ </div>
947
+ <div class="listingblock">
948
+ <div class="content">
949
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn rebase
950
+ Committing to file:///tmp/test-svn/trunk ...
951
+
952
+ ERROR from SVN:
953
+ Transaction is out of date: File '/trunk/README.txt' is out of date
954
+ W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk differ, using rebase:
955
+ :100644 100644 65536c6e30d263495c17d781962cfff12422693a b34372b25ccf4945fe5658fa381b075045e7702a M README.txt
956
+ First, rewinding head to replay your work on top of it...
957
+ Applying: update foo
958
+ Using index info to reconstruct a base tree...
959
+ M README.txt
960
+ Falling back to patching base and 3-way merge...
961
+ Auto-merging README.txt
962
+ ERROR: Not all changes have been committed into SVN, however the committed
963
+ ones (if any) seem to be successfully integrated into the working tree.
964
+ Please see the above messages for details.</code></pre>
965
+ </div>
966
+ </div>
967
+ <div class="paragraph">
968
+ <p>Now, all your work is on top of what is on the Subversion server, so you can successfully <code>dcommit</code>:</p>
969
+ </div>
970
+ <div class="listingblock">
971
+ <div class="content">
972
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit
973
+ Committing to file:///tmp/test-svn/trunk ...
974
+ M README.txt
975
+ Committed r85
976
+ M README.txt
977
+ r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk)
978
+ No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and refs/remotes/origin/trunk
979
+ Resetting to the latest refs/remotes/origin/trunk</code></pre>
980
+ </div>
981
+ </div>
982
+ <div class="paragraph">
983
+ <p>Note that unlike Git, which requires you to merge upstream work you don’t yet have locally before you can push, <code>git svn</code> makes you do that only if the changes conflict (much like how Subversion works).
984
+ If someone else pushes a change to one file and then you push a change to another file, your <code>dcommit</code> will work fine:</p>
985
+ </div>
986
+ <div class="listingblock">
987
+ <div class="content">
988
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit
989
+ Committing to file:///tmp/test-svn/trunk ...
990
+ M configure.ac
991
+ Committed r87
992
+ M autogen.sh
993
+ r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
994
+ M configure.ac
995
+ r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk)
996
+ W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk differ, using rebase:
997
+ :100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 e757b59a9439312d80d5d43bb65d4a7d0389ed6d M autogen.sh
998
+ First, rewinding head to replay your work on top of it...</code></pre>
999
+ </div>
1000
+ </div>
1001
+ <div class="paragraph">
1002
+ <p>This is important to remember, because the outcome is a project state that didn’t exist on either of your computers when you pushed.
1003
+ If the changes are incompatible but don’t conflict, you may get issues that are difficult to diagnose.
1004
+ This is different than using a Git server – in Git, you can fully test the state on your client system before publishing it, whereas in SVN, you can’t ever be certain that the states immediately before commit and after commit are identical.</p>
1005
+ </div>
1006
+ <div class="paragraph">
1007
+ <p>You should also run this command to pull in changes from the Subversion server, even if you’re not ready to commit yourself.
1008
+ You can run <code>git svn fetch</code> to grab the new data, but <code>git svn rebase</code> does the fetch and then updates your local commits.</p>
1009
+ </div>
1010
+ <div class="listingblock">
1011
+ <div class="content">
1012
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn rebase
1013
+ M autogen.sh
1014
+ r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk)
1015
+ First, rewinding head to replay your work on top of it...
1016
+ Fast-forwarded master to refs/remotes/origin/trunk.</code></pre>
1017
+ </div>
1018
+ </div>
1019
+ <div class="paragraph">
1020
+ <p>Running <code>git svn rebase</code> every once in a while makes sure your code is always up to date.
1021
+ You need to be sure your working directory is clean when you run this, though.
1022
+ If you have local changes, you must either stash your work or temporarily commit it before running <code>git svn rebase</code> – otherwise, the command will stop if it sees that the rebase will result in a merge conflict.</p>
1023
+ </div>
1024
+ </div>
1025
+ <div class="sect4">
1026
+ <h4 id="_git_branching_issues">Git Branching Issues</h4>
1027
+ <div class="paragraph">
1028
+ <p>When you’ve become comfortable with a Git workflow, you’ll likely create topic branches, do work on them, and then merge them in.
1029
+ If you’re pushing to a Subversion server via <code>git svn</code>, you may want to rebase your work onto a single branch each time instead of merging branches together.
1030
+ The reason to prefer rebasing is that Subversion has a linear history and doesn’t deal with merges like Git does, so <code>git svn</code> follows only the first parent when converting the snapshots into Subversion commits.</p>
1031
+ </div>
1032
+ <div class="paragraph">
1033
+ <p>Suppose your history looks like the following: you created an <code>experiment</code> branch, did two commits, and then merged them back into <code>master</code>.
1034
+ When you <code>dcommit</code>, you see output like this:</p>
1035
+ </div>
1036
+ <div class="listingblock">
1037
+ <div class="content">
1038
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit
1039
+ Committing to file:///tmp/test-svn/trunk ...
1040
+ M CHANGES.txt
1041
+ Committed r89
1042
+ M CHANGES.txt
1043
+ r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk)
1044
+ M COPYING.txt
1045
+ M INSTALL.txt
1046
+ Committed r90
1047
+ M INSTALL.txt
1048
+ M COPYING.txt
1049
+ r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk)
1050
+ No changes between 71af502c214ba13123992338569f4669877f55fd and refs/remotes/origin/trunk
1051
+ Resetting to the latest refs/remotes/origin/trunk</code></pre>
1052
+ </div>
1053
+ </div>
1054
+ <div class="paragraph">
1055
+ <p>Running <code>dcommit</code> on a branch with merged history works fine, except that when you look at your Git project history, it hasn’t rewritten either of the commits you made on the <code>experiment</code> branch – instead, all those changes appear in the SVN version of the single merge commit.</p>
1056
+ </div>
1057
+ <div class="paragraph">
1058
+ <p>When someone else clones that work, all they see is the merge commit with all the work squashed into it, as though you ran <code>git merge --squash</code>; they don’t see the commit data about where it came from or when it was committed.</p>
1059
+ </div>
1060
+ </div>
1061
+ <div class="sect4">
1062
+ <h4 id="_subversion_branching">Subversion Branching</h4>
1063
+ <div class="paragraph">
1064
+ <p>Branching in Subversion isn’t the same as branching in Git; if you can avoid using it much, that’s probably best.
1065
+ However, you can create and commit to branches in Subversion using <code>git svn</code>.</p>
1066
+ </div>
1067
+ </div>
1068
+ <div class="sect4">
1069
+ <h4 id="_creating_a_new_svn_branch">Creating a New SVN Branch</h4>
1070
+ <div class="paragraph">
1071
+ <p>To create a new branch in Subversion, you run <code>git svn branch [new-branch]</code>:</p>
1072
+ </div>
1073
+ <div class="listingblock">
1074
+ <div class="content">
1075
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn branch opera
1076
+ Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-svn/branches/opera...
1077
+ Found possible branch point: file:///tmp/test-svn/trunk =&gt; file:///tmp/test-svn/branches/opera, 90
1078
+ Found branch parent: (refs/remotes/origin/opera) cb522197870e61467473391799148f6721bcf9a0
1079
+ Following parent with do_switch
1080
+ Successfully followed parent
1081
+ r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)</code></pre>
1082
+ </div>
1083
+ </div>
1084
+ <div class="paragraph">
1085
+ <p>This does the equivalent of the <code>svn copy trunk branches/opera</code> command in Subversion and operates on the Subversion server.
1086
+ It’s important to note that it doesn’t check you out into that branch; if you commit at this point, that commit will go to <code>trunk</code> on the server, not <code>opera</code>.</p>
1087
+ </div>
1088
+ </div>
1089
+ <div class="sect4">
1090
+ <h4 id="_switching_active_branches">Switching Active Branches</h4>
1091
+ <div class="paragraph">
1092
+ <p>Git figures out what branch your dcommits go to by looking for the tip of any of your Subversion branches in your history – you should have only one, and it should be the last one with a <code>git-svn-id</code> in your current branch history.</p>
1093
+ </div>
1094
+ <div class="paragraph">
1095
+ <p>If you want to work on more than one branch simultaneously, you can set up local branches to <code>dcommit</code> to specific Subversion branches by starting them at the imported Subversion commit for that branch.
1096
+ If you want an <code>opera</code> branch that you can work on separately, you can run:</p>
1097
+ </div>
1098
+ <div class="listingblock">
1099
+ <div class="content">
1100
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git branch opera remotes/origin/opera</code></pre>
1101
+ </div>
1102
+ </div>
1103
+ <div class="paragraph">
1104
+ <p>Now, if you want to merge your <code>opera</code> branch into <code>trunk</code> (your <code>master</code> branch), you can do so with a normal <code>git merge</code>.
1105
+ But you need to provide a descriptive commit message (via <code>-m</code>), or the merge will say “Merge branch opera” instead of something useful.</p>
1106
+ </div>
1107
+ <div class="paragraph">
1108
+ <p>Remember that although you’re using <code>git merge</code> to do this operation, and the merge likely will be much easier than it would be in Subversion (because Git will automatically detect the appropriate merge base for you), this isn’t a normal Git merge commit.
1109
+ You have to push this data back to a Subversion server that can’t handle a commit that tracks more than one parent; so, after you push it up, it will look like a single commit that squashed in all the work of another branch under a single commit.
1110
+ After you merge one branch into another, you can’t easily go back and continue working on that branch, as you normally can in Git.
1111
+ The <code>dcommit</code> command that you run erases any information that says what branch was merged in, so subsequent merge-base calculations will be wrong – the <code>dcommit</code> makes your <code>git merge</code> result look like you ran <code>git merge --squash</code>.
1112
+ Unfortunately, there’s no good way to avoid this situation – Subversion can’t store this information, so you’ll always be crippled by its limitations while you’re using it as your server.
1113
+ To avoid issues, you should delete the local branch (in this case, <code>opera</code>) after you merge it into trunk.</p>
1114
+ </div>
1115
+ </div>
1116
+ <div class="sect4">
1117
+ <h4 id="_subversion_commands">Subversion Commands</h4>
1118
+ <div class="paragraph">
1119
+ <p>The <code>git svn</code> toolset provides a number of commands to help ease the transition to Git by providing some functionality that’s similar to what you had in Subversion.
1120
+ Here are a few commands that give you what Subversion used to.</p>
1121
+ </div>
1122
+ <div class="sect5">
1123
+ <h6 id="_svn_style_history">SVN Style History</h6>
1124
+ <div class="paragraph">
1125
+ <p>If you’re used to Subversion and want to see your history in SVN output style, you can run <code>git svn log</code> to view your commit history in SVN formatting:</p>
1126
+ </div>
1127
+ <div class="listingblock">
1128
+ <div class="content">
1129
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn log
1130
+ ------------------------------------------------------------------------
1131
+ r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines
1132
+
1133
+ autogen change
1134
+
1135
+ ------------------------------------------------------------------------
1136
+ r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines
1137
+
1138
+ Merge branch 'experiment'
1139
+
1140
+ ------------------------------------------------------------------------
1141
+ r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines
1142
+
1143
+ updated the changelog</code></pre>
1144
+ </div>
1145
+ </div>
1146
+ <div class="paragraph">
1147
+ <p>You should know two important things about <code>git svn log</code>.
1148
+ First, it works offline, unlike the real <code>svn log</code> command, which asks the Subversion server for the data.
1149
+ Second, it only shows you commits that have been committed up to the Subversion server.
1150
+ Local Git commits that you haven’t dcommited don’t show up; neither do commits that people have made to the Subversion server in the meantime.
1151
+ It’s more like the last known state of the commits on the Subversion server.</p>
1152
+ </div>
1153
+ </div>
1154
+ <div class="sect5">
1155
+ <h6 id="_svn_annotation">SVN Annotation</h6>
1156
+ <div class="paragraph">
1157
+ <p>Much as the <code>git svn log</code> command simulates the <code>svn log</code> command offline, you can get the equivalent of <code>svn annotate</code> by running <code>git svn blame [FILE]</code>.
1158
+ The output looks like this:</p>
1159
+ </div>
1160
+ <div class="listingblock">
1161
+ <div class="content">
1162
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn blame README.txt
1163
+ 2 temporal Protocol Buffers - Google's data interchange format
1164
+ 2 temporal Copyright 2008 Google Inc.
1165
+ 2 temporal http://code.google.com/apis/protocolbuffers/
1166
+ 2 temporal
1167
+ 22 temporal C++ Installation - Unix
1168
+ 22 temporal =======================
1169
+ 2 temporal
1170
+ 79 schacon Committing in git-svn.
1171
+ 78 schacon
1172
+ 2 temporal To build and install the C++ Protocol Buffer runtime and the Protocol
1173
+ 2 temporal Buffer compiler (protoc) execute the following:
1174
+ 2 temporal</code></pre>
1175
+ </div>
1176
+ </div>
1177
+ <div class="paragraph">
1178
+ <p>Again, it doesn’t show commits that you did locally in Git or that have been pushed to Subversion in the meantime.</p>
1179
+ </div>
1180
+ </div>
1181
+ <div class="sect5">
1182
+ <h6 id="_svn_server_information">SVN Server Information</h6>
1183
+ <div class="paragraph">
1184
+ <p>You can also get the same sort of information that <code>svn info</code> gives you by running <code>git svn info</code>:</p>
1185
+ </div>
1186
+ <div class="listingblock">
1187
+ <div class="content">
1188
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn info
1189
+ Path: .
1190
+ URL: https://schacon-test.googlecode.com/svn/trunk
1191
+ Repository Root: https://schacon-test.googlecode.com/svn
1192
+ Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
1193
+ Revision: 87
1194
+ Node Kind: directory
1195
+ Schedule: normal
1196
+ Last Changed Author: schacon
1197
+ Last Changed Rev: 87
1198
+ Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)</code></pre>
1199
+ </div>
1200
+ </div>
1201
+ <div class="paragraph">
1202
+ <p>This is like <code>blame</code> and <code>log</code> in that it runs offline and is up to date only as of the last time you communicated with the Subversion server.</p>
1203
+ </div>
1204
+ </div>
1205
+ <div class="sect5">
1206
+ <h6 id="_ignoring_what_subversion_ignores">Ignoring What Subversion Ignores</h6>
1207
+ <div class="paragraph">
1208
+ <p>If you clone a Subversion repository that has <code>svn:ignore</code> properties set anywhere, you’ll likely want to set corresponding <code>.gitignore</code> files so you don’t accidentally commit files that you shouldn’t.
1209
+ <code>git svn</code> has two commands to help with this issue.
1210
+ The first is <code>git svn create-ignore</code>, which automatically creates corresponding <code>.gitignore</code> files for you so your next commit can include them.</p>
1211
+ </div>
1212
+ <div class="paragraph">
1213
+ <p>The second command is <code>git svn show-ignore</code>, which prints to stdout the lines you need to put in a <code>.gitignore</code> file so you can redirect the output into your project exclude file:</p>
1214
+ </div>
1215
+ <div class="listingblock">
1216
+ <div class="content">
1217
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git svn show-ignore &gt; .git/info/exclude</code></pre>
1218
+ </div>
1219
+ </div>
1220
+ <div class="paragraph">
1221
+ <p>That way, you don’t litter the project with <code>.gitignore</code> files.
1222
+ This is a good option if you’re the only Git user on a Subversion team, and your teammates don’t want <code>.gitignore</code> files in the project.</p>
1223
+ </div>
1224
+ </div>
1225
+ </div>
1226
+ <div class="sect4">
1227
+ <h4 id="_git_svn_summary">Git-Svn Summary</h4>
1228
+ <div class="paragraph">
1229
+ <p>The <code>git svn</code> tools are useful if you’re stuck with a Subversion server, or are otherwise in a development environment that necessitates running a Subversion server.
1230
+ You should consider it crippled Git, however, or you’ll hit issues in translation that may confuse you and your collaborators.
1231
+ To stay out of trouble, try to follow these guidelines:</p>
1232
+ </div>
1233
+ <div class="ulist">
1234
+ <ul>
1235
+ <li>
1236
+ <p>Keep a linear Git history that doesn’t contain merge commits made by <code>git merge</code>.
1237
+ Rebase any work you do outside of your mainline branch back onto it; don’t merge it in.</p>
1238
+ </li>
1239
+ <li>
1240
+ <p>Don’t set up and collaborate on a separate Git server.
1241
+ Possibly have one to speed up clones for new developers, but don’t push anything to it that doesn’t have a <code>git-svn-id</code> entry.
1242
+ You may even want to add a <code>pre-receive</code> hook that checks each commit message for a <code>git-svn-id</code> and rejects pushes that contain commits without it.</p>
1243
+ </li>
1244
+ </ul>
1245
+ </div>
1246
+ <div class="paragraph">
1247
+ <p>If you follow those guidelines, working with a Subversion server can be more bearable.
1248
+ However, if it’s possible to move to a real Git server, doing so can gain your team a lot more.</p>
1249
+ </div>
1250
+ </div>
1251
+ </div>
1252
+ <div class="sect3">
1253
+ <h3 id="_git_and_mercurial">Git and Mercurial</h3>
1254
+ <div class="paragraph">
1255
+ <p>
1256
+
1257
+ The DVCS universe is larger than just Git.
1258
+ In fact, there are many other systems in this space, each with their own angle on how to do distributed version control correctly.
1259
+ Apart from Git, the most popular is Mercurial, and the two are very similar in many respects.</p>
1260
+ </div>
1261
+ <div class="paragraph">
1262
+ <p>The good news, if you prefer Git’s client-side behavior but are working with a project whose source code is controlled with Mercurial, is that there’s a way to use Git as a client for a Mercurial-hosted repository.
1263
+ Since the way Git talks to server repositories is through remotes, it should come as no surprise that this bridge is implemented as a remote helper.
1264
+ The project’s name is git-remote-hg, and it can be found at <a href="https://github.com/felipec/git-remote-hg" class="bare">https://github.com/felipec/git-remote-hg</a>.</p>
1265
+ </div>
1266
+ <div class="sect4">
1267
+ <h4 id="_git_remote_hg">git-remote-hg</h4>
1268
+ <div class="paragraph">
1269
+ <p>First, you need to install git-remote-hg.
1270
+ This basically entails dropping its file somewhere in your path, like so:</p>
1271
+ </div>
1272
+ <div class="listingblock">
1273
+ <div class="content">
1274
+ <pre class="highlight"><code class="language-console" data-lang="console">$ curl -o ~/bin/git-remote-hg \
1275
+ https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg
1276
+ $ chmod +x ~/bin/git-remote-hg</code></pre>
1277
+ </div>
1278
+ </div>
1279
+ <div class="paragraph">
1280
+ <p>…assuming <code>~/bin</code> is in your <code>$PATH</code>.
1281
+ Git-remote-hg has one other dependency: the <code>mercurial</code> library for Python.
1282
+ If you have Python installed, this is as simple as:</p>
1283
+ </div>
1284
+ <div class="listingblock">
1285
+ <div class="content">
1286
+ <pre class="highlight"><code class="language-console" data-lang="console">$ pip install mercurial</code></pre>
1287
+ </div>
1288
+ </div>
1289
+ <div class="paragraph">
1290
+ <p>If you don’t have Python installed, visit <a href="https://www.python.org/" class="bare">https://www.python.org/</a> and get it first.</p>
1291
+ </div>
1292
+ <div class="paragraph">
1293
+ <p>The last thing you’ll need is the Mercurial client.
1294
+ Go to <a href="https://www.mercurial-scm.org/" class="bare">https://www.mercurial-scm.org/</a> and install it if you haven’t already.</p>
1295
+ </div>
1296
+ <div class="paragraph">
1297
+ <p>Now you’re ready to rock.
1298
+ All you need is a Mercurial repository you can push to.
1299
+ Fortunately, every Mercurial repository can act this way, so we’ll just use the "hello world" repository everyone uses to learn Mercurial:</p>
1300
+ </div>
1301
+ <div class="listingblock">
1302
+ <div class="content">
1303
+ <pre class="highlight"><code class="language-console" data-lang="console">$ hg clone http://selenic.com/repo/hello /tmp/hello</code></pre>
1304
+ </div>
1305
+ </div>
1306
+ </div>
1307
+ <div class="sect4">
1308
+ <h4 id="_getting_started_2">Getting Started</h4>
1309
+ <div class="paragraph">
1310
+ <p>Now that we have a suitable “server-side” repository, we can go through a typical workflow.
1311
+ As you’ll see, these two systems are similar enough that there isn’t much friction.</p>
1312
+ </div>
1313
+ <div class="paragraph">
1314
+ <p>As always with Git, first we clone:</p>
1315
+ </div>
1316
+ <div class="listingblock">
1317
+ <div class="content">
1318
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git clone hg::/tmp/hello /tmp/hello-git
1319
+ $ cd /tmp/hello-git
1320
+ $ git log --oneline --graph --decorate
1321
+ * ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master) Create a makefile
1322
+ * 65bb417 Create a standard 'hello, world' program</code></pre>
1323
+ </div>
1324
+ </div>
1325
+ <div class="paragraph">
1326
+ <p>You’ll notice that working with a Mercurial repository uses the standard <code>git clone</code> command.
1327
+ That’s because git-remote-hg is working at a fairly low level, using a similar mechanism to how Git’s HTTP/S protocol is implemented (remote helpers).
1328
+ Since Git and Mercurial are both designed for every client to have a full copy of the repository history, this command makes a full clone, including all the project’s history, and does it fairly quickly.</p>
1329
+ </div>
1330
+ <div class="paragraph">
1331
+ <p>The log command shows two commits, the latest of which is pointed to by a whole slew of refs.
1332
+ It turns out some of these aren’t actually there.
1333
+ Let’s take a look at what’s actually in the <code>.git</code> directory:</p>
1334
+ </div>
1335
+ <div class="listingblock">
1336
+ <div class="content">
1337
+ <pre class="highlight"><code class="language-console" data-lang="console">$ tree .git/refs
1338
+ .git/refs
1339
+ ├── heads
1340
+ │   └── master
1341
+ ├── hg
1342
+ │   └── origin
1343
+ │   ├── bookmarks
1344
+ │   │   └── master
1345
+ │   └── branches
1346
+ │   └── default
1347
+ ├── notes
1348
+ │   └── hg
1349
+ ├── remotes
1350
+ │   └── origin
1351
+ │   └── HEAD
1352
+ └── tags
1353
+
1354
+ 9 directories, 5 files</code></pre>
1355
+ </div>
1356
+ </div>
1357
+ <div class="paragraph">
1358
+ <p>Git-remote-hg is trying to make things more idiomatically Git-esque, but under the hood it’s managing the conceptual mapping between two slightly different systems.
1359
+ The <code>refs/hg</code> directory is where the actual remote refs are stored.
1360
+ For example, the <code>refs/hg/origin/branches/default</code> is a Git ref file that contains the SHA-1 starting with “ac7955c”, which is the commit that <code>master</code> points to.
1361
+ So the <code>refs/hg</code> directory is kind of like a fake <code>refs/remotes/origin</code>, but it has the added distinction between bookmarks and branches.</p>
1362
+ </div>
1363
+ <div class="paragraph">
1364
+ <p>The <code>notes/hg</code> file is the starting point for how git-remote-hg maps Git commit hashes to Mercurial changeset IDs.
1365
+ Let’s explore a bit:</p>
1366
+ </div>
1367
+ <div class="listingblock">
1368
+ <div class="content">
1369
+ <pre class="highlight"><code class="language-console" data-lang="console">$ cat notes/hg
1370
+ d4c10386...
1371
+
1372
+ $ git cat-file -p d4c10386...
1373
+ tree 1781c96...
1374
+ author remote-hg &lt;&gt; 1408066400 -0800
1375
+ committer remote-hg &lt;&gt; 1408066400 -0800
1376
+
1377
+ Notes for master
1378
+
1379
+ $ git ls-tree 1781c96...
1380
+ 100644 blob ac9117f... 65bb417...
1381
+ 100644 blob 485e178... ac7955c...
1382
+
1383
+ $ git cat-file -p ac9117f
1384
+ 0a04b987be5ae354b710cefeba0e2d9de7ad41a9</code></pre>
1385
+ </div>
1386
+ </div>
1387
+ <div class="paragraph">
1388
+ <p>So <code>refs/notes/hg</code> points to a tree, which in the Git object database is a list of other objects with names.
1389
+ <code>git ls-tree</code> outputs the mode, type, object hash, and filename for items inside a tree.
1390
+ Once we dig down to one of the tree items, we find that inside it is a blob named “ac9117f” (the SHA-1 hash of the commit pointed to by <code>master</code>), with contents “0a04b98” (which is the ID of the Mercurial changeset at the tip of the <code>default</code> branch).</p>
1391
+ </div>
1392
+ <div class="paragraph">
1393
+ <p>The good news is that we mostly don’t have to worry about all of this.
1394
+ The typical workflow won’t be very different from working with a Git remote.</p>
1395
+ </div>
1396
+ <div class="paragraph">
1397
+ <p>There’s one more thing we should attend to before we continue: ignores.
1398
+ Mercurial and Git use a very similar mechanism for this, but it’s likely you don’t want to actually commit a <code>.gitignore</code> file into a Mercurial repository.
1399
+ Fortunately, Git has a way to ignore files that’s local to an on-disk repository, and the Mercurial format is compatible with Git, so you just have to copy it over:</p>
1400
+ </div>
1401
+ <div class="listingblock">
1402
+ <div class="content">
1403
+ <pre class="highlight"><code class="language-console" data-lang="console">$ cp .hgignore .git/info/exclude</code></pre>
1404
+ </div>
1405
+ </div>
1406
+ <div class="paragraph">
1407
+ <p>The <code>.git/info/exclude</code> file acts just like a <code>.gitignore</code>, but isn’t included in commits.</p>
1408
+ </div>
1409
+ </div>
1410
+ <div class="sect4">
1411
+ <h4 id="_workflow">Workflow</h4>
1412
+ <div class="paragraph">
1413
+ <p>Let’s assume we’ve done some work and made some commits on the <code>master</code> branch, and you’re ready to push it to the remote repository.
1414
+ Here’s what our repository looks like right now:</p>
1415
+ </div>
1416
+ <div class="listingblock">
1417
+ <div class="content">
1418
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git log --oneline --graph --decorate
1419
+ * ba04a2a (HEAD, master) Update makefile
1420
+ * d25d16f Goodbye
1421
+ * ac7955c (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a makefile
1422
+ * 65bb417 Create a standard 'hello, world' program</code></pre>
1423
+ </div>
1424
+ </div>
1425
+ <div class="paragraph">
1426
+ <p>Our <code>master</code> branch is two commits ahead of <code>origin/master</code>, but those two commits exist only on our local machine.
1427
+ Let’s see if anyone else has been doing important work at the same time:</p>
1428
+ </div>
1429
+ <div class="listingblock">
1430
+ <div class="content">
1431
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch
1432
+ From hg::/tmp/hello
1433
+ ac7955c..df85e87 master -&gt; origin/master
1434
+ ac7955c..df85e87 branches/default -&gt; origin/branches/default
1435
+ $ git log --oneline --graph --decorate --all
1436
+ * 7b07969 (refs/notes/hg) Notes for default
1437
+ * d4c1038 Notes for master
1438
+ * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
1439
+ | * ba04a2a (HEAD, master) Update makefile
1440
+ | * d25d16f Goodbye
1441
+ |/
1442
+ * ac7955c Create a makefile
1443
+ * 65bb417 Create a standard 'hello, world' program</code></pre>
1444
+ </div>
1445
+ </div>
1446
+ <div class="paragraph">
1447
+ <p>Since we used the <code>--all</code> flag, we see the “notes” refs that are used internally by git-remote-hg, but we can ignore them.
1448
+ The rest is what we expected; <code>origin/master</code> has advanced by one commit, and our history has now diverged.
1449
+ Unlike the other systems we work with in this chapter, Mercurial is capable of handling merges, so we’re not going to do anything fancy.</p>
1450
+ </div>
1451
+ <div class="listingblock">
1452
+ <div class="content">
1453
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master
1454
+ Auto-merging hello.c
1455
+ Merge made by the 'recursive' strategy.
1456
+ hello.c | 2 +-
1457
+ 1 file changed, 1 insertion(+), 1 deletion(-)
1458
+ $ git log --oneline --graph --decorate
1459
+ * 0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master'
1460
+ |\
1461
+ | * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
1462
+ * | ba04a2a Update makefile
1463
+ * | d25d16f Goodbye
1464
+ |/
1465
+ * ac7955c Create a makefile
1466
+ * 65bb417 Create a standard 'hello, world' program</code></pre>
1467
+ </div>
1468
+ </div>
1469
+ <div class="paragraph">
1470
+ <p>Perfect.
1471
+ We run the tests and everything passes, so we’re ready to share our work with the rest of the team:</p>
1472
+ </div>
1473
+ <div class="listingblock">
1474
+ <div class="content">
1475
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git push
1476
+ To hg::/tmp/hello
1477
+ df85e87..0c64627 master -&gt; master</code></pre>
1478
+ </div>
1479
+ </div>
1480
+ <div class="paragraph">
1481
+ <p>That’s it!
1482
+ If you take a look at the Mercurial repository, you’ll see that this did what we’d expect:</p>
1483
+ </div>
1484
+ <div class="listingblock">
1485
+ <div class="content">
1486
+ <pre class="highlight"><code class="language-console" data-lang="console">$ hg log -G --style compact
1487
+ o 5[tip]:4,2 dc8fa4f932b8 2014-08-14 19:33 -0700 ben
1488
+ |\ Merge remote-tracking branch 'origin/master'
1489
+ | |
1490
+ | o 4 64f27bcefc35 2014-08-14 19:27 -0700 ben
1491
+ | | Update makefile
1492
+ | |
1493
+ | o 3:1 4256fc29598f 2014-08-14 19:27 -0700 ben
1494
+ | | Goodbye
1495
+ | |
1496
+ @ | 2 7db0b4848b3c 2014-08-14 19:30 -0700 ben
1497
+ |/ Add some documentation
1498
+ |
1499
+ o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm
1500
+ | Create a makefile
1501
+ |
1502
+ o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm
1503
+ Create a standard 'hello, world' program</code></pre>
1504
+ </div>
1505
+ </div>
1506
+ <div class="paragraph">
1507
+ <p>The changeset numbered <em>2</em> was made by Mercurial, and the changesets numbered <em>3</em> and <em>4</em> were made by git-remote-hg, by pushing commits made with Git.</p>
1508
+ </div>
1509
+ </div>
1510
+ <div class="sect4">
1511
+ <h4 id="_branches_and_bookmarks">Branches and Bookmarks</h4>
1512
+ <div class="paragraph">
1513
+ <p>Git has only one kind of branch: a reference that moves when commits are made.
1514
+ In Mercurial, this kind of a reference is called a “bookmark,” and it behaves in much the same way as a Git branch.</p>
1515
+ </div>
1516
+ <div class="paragraph">
1517
+ <p>Mercurial’s concept of a “branch” is more heavyweight.
1518
+ The branch that a changeset is made on is recorded <em>with the changeset</em>, which means it will always be in the repository history.
1519
+ Here’s an example of a commit that was made on the <code>develop</code> branch:</p>
1520
+ </div>
1521
+ <div class="listingblock">
1522
+ <div class="content">
1523
+ <pre class="highlight"><code class="language-console" data-lang="console">$ hg log -l 1
1524
+ changeset: 6:8f65e5e02793
1525
+ branch: develop
1526
+ tag: tip
1527
+ user: Ben Straub &lt;ben@straub.cc&gt;
1528
+ date: Thu Aug 14 20:06:38 2014 -0700
1529
+ summary: More documentation</code></pre>
1530
+ </div>
1531
+ </div>
1532
+ <div class="paragraph">
1533
+ <p>Note the line that begins with “branch”.
1534
+ Git can’t really replicate this (and doesn’t need to; both types of branch can be represented as a Git ref), but git-remote-hg needs to understand the difference, because Mercurial cares.</p>
1535
+ </div>
1536
+ <div class="paragraph">
1537
+ <p>Creating Mercurial bookmarks is as easy as creating Git branches.
1538
+ On the Git side:</p>
1539
+ </div>
1540
+ <div class="listingblock">
1541
+ <div class="content">
1542
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b featureA
1543
+ Switched to a new branch 'featureA'
1544
+ $ git push origin featureA
1545
+ To hg::/tmp/hello
1546
+ * [new branch] featureA -&gt; featureA</code></pre>
1547
+ </div>
1548
+ </div>
1549
+ <div class="paragraph">
1550
+ <p>That’s all there is to it.
1551
+ On the Mercurial side, it looks like this:</p>
1552
+ </div>
1553
+ <div class="listingblock">
1554
+ <div class="content">
1555
+ <pre class="highlight"><code class="language-console" data-lang="console">$ hg bookmarks
1556
+ featureA 5:bd5ac26f11f9
1557
+ $ hg log --style compact -G
1558
+ @ 6[tip] 8f65e5e02793 2014-08-14 20:06 -0700 ben
1559
+ | More documentation
1560
+ |
1561
+ o 5[featureA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben
1562
+ |\ Merge remote-tracking branch 'origin/master'
1563
+ | |
1564
+ | o 4 0434aaa6b91f 2014-08-14 20:01 -0700 ben
1565
+ | | update makefile
1566
+ | |
1567
+ | o 3:1 318914536c86 2014-08-14 20:00 -0700 ben
1568
+ | | goodbye
1569
+ | |
1570
+ o | 2 f098c7f45c4f 2014-08-14 20:01 -0700 ben
1571
+ |/ Add some documentation
1572
+ |
1573
+ o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm
1574
+ | Create a makefile
1575
+ |
1576
+ o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm
1577
+ Create a standard 'hello, world' program</code></pre>
1578
+ </div>
1579
+ </div>
1580
+ <div class="paragraph">
1581
+ <p>Note the new <code>[featureA]</code> tag on revision 5.
1582
+ These act exactly like Git branches on the Git side, with one exception: you can’t delete a bookmark from the Git side (this is a limitation of remote helpers).</p>
1583
+ </div>
1584
+ <div class="paragraph">
1585
+ <p>You can work on a “heavyweight” Mercurial branch also: just put a branch in the <code>branches</code> namespace:</p>
1586
+ </div>
1587
+ <div class="listingblock">
1588
+ <div class="content">
1589
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b branches/permanent
1590
+ Switched to a new branch 'branches/permanent'
1591
+ $ vi Makefile
1592
+ $ git commit -am 'A permanent change'
1593
+ $ git push origin branches/permanent
1594
+ To hg::/tmp/hello
1595
+ * [new branch] branches/permanent -&gt; branches/permanent</code></pre>
1596
+ </div>
1597
+ </div>
1598
+ <div class="paragraph">
1599
+ <p>Here’s what that looks like on the Mercurial side:</p>
1600
+ </div>
1601
+ <div class="listingblock">
1602
+ <div class="content">
1603
+ <pre class="highlight"><code class="language-console" data-lang="console">$ hg branches
1604
+ permanent 7:a4529d07aad4
1605
+ develop 6:8f65e5e02793
1606
+ default 5:bd5ac26f11f9 (inactive)
1607
+ $ hg log -G
1608
+ o changeset: 7:a4529d07aad4
1609
+ | branch: permanent
1610
+ | tag: tip
1611
+ | parent: 5:bd5ac26f11f9
1612
+ | user: Ben Straub &lt;ben@straub.cc&gt;
1613
+ | date: Thu Aug 14 20:21:09 2014 -0700
1614
+ | summary: A permanent change
1615
+ |
1616
+ | @ changeset: 6:8f65e5e02793
1617
+ |/ branch: develop
1618
+ | user: Ben Straub &lt;ben@straub.cc&gt;
1619
+ | date: Thu Aug 14 20:06:38 2014 -0700
1620
+ | summary: More documentation
1621
+ |
1622
+ o changeset: 5:bd5ac26f11f9
1623
+ |\ bookmark: featureA
1624
+ | | parent: 4:0434aaa6b91f
1625
+ | | parent: 2:f098c7f45c4f
1626
+ | | user: Ben Straub &lt;ben@straub.cc&gt;
1627
+ | | date: Thu Aug 14 20:02:21 2014 -0700
1628
+ | | summary: Merge remote-tracking branch 'origin/master'
1629
+ [...]</code></pre>
1630
+ </div>
1631
+ </div>
1632
+ <div class="paragraph">
1633
+ <p>The branch name “permanent” was recorded with the changeset marked <em>7</em>.</p>
1634
+ </div>
1635
+ <div class="paragraph">
1636
+ <p>From the Git side, working with either of these branch styles is the same: just checkout, commit, fetch, merge, pull, and push as you normally would.
1637
+ One thing you should know is that Mercurial doesn’t support rewriting history, only adding to it.
1638
+ Here’s what our Mercurial repository looks like after an interactive rebase and a force-push:</p>
1639
+ </div>
1640
+ <div class="listingblock">
1641
+ <div class="content">
1642
+ <pre class="highlight"><code class="language-console" data-lang="console">$ hg log --style compact -G
1643
+ o 10[tip] 99611176cbc9 2014-08-14 20:21 -0700 ben
1644
+ | A permanent change
1645
+ |
1646
+ o 9 f23e12f939c3 2014-08-14 20:01 -0700 ben
1647
+ | Add some documentation
1648
+ |
1649
+ o 8:1 c16971d33922 2014-08-14 20:00 -0700 ben
1650
+ | goodbye
1651
+ |
1652
+ | o 7:5 a4529d07aad4 2014-08-14 20:21 -0700 ben
1653
+ | | A permanent change
1654
+ | |
1655
+ | | @ 6 8f65e5e02793 2014-08-14 20:06 -0700 ben
1656
+ | |/ More documentation
1657
+ | |
1658
+ | o 5[featureA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben
1659
+ | |\ Merge remote-tracking branch 'origin/master'
1660
+ | | |
1661
+ | | o 4 0434aaa6b91f 2014-08-14 20:01 -0700 ben
1662
+ | | | update makefile
1663
+ | | |
1664
+ +---o 3:1 318914536c86 2014-08-14 20:00 -0700 ben
1665
+ | | goodbye
1666
+ | |
1667
+ | o 2 f098c7f45c4f 2014-08-14 20:01 -0700 ben
1668
+ |/ Add some documentation
1669
+ |
1670
+ o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm
1671
+ | Create a makefile
1672
+ |
1673
+ o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm
1674
+ Create a standard "hello, world" program</code></pre>
1675
+ </div>
1676
+ </div>
1677
+ <div class="paragraph">
1678
+ <p>Changesets <em>8</em>, <em>9</em>, and <em>10</em> have been created and belong to the <code>permanent</code> branch, but the old changesets are still there.
1679
+ This can be <strong>very</strong> confusing for your teammates who are using Mercurial, so try to avoid it.</p>
1680
+ </div>
1681
+ </div>
1682
+ <div class="sect4">
1683
+ <h4 id="_mercurial_summary">Mercurial Summary</h4>
1684
+ <div class="paragraph">
1685
+ <p>Git and Mercurial are similar enough that working across the boundary is fairly painless.
1686
+ If you avoid changing history that’s left your machine (as is generally recommended), you may not even be aware that the other end is Mercurial.</p>
1687
+ </div>
1688
+ </div>
1689
+ </div>
1690
+ <div class="sect3">
1691
+ <h3 id="_git_and_bazaar">Git and Bazaar</h3>
1692
+ <div class="paragraph">
1693
+ <p>Among the DVCS, another famous one is <a href="http://bazaar.canonical.com">Bazaar</a>.
1694
+ Bazaar is free and open source, and is part of the <a href="https://www.gnu.org">GNU Project</a>.
1695
+ It behaves very differently from Git.
1696
+ Sometimes, to do the same thing as with Git, you have to use a different keyword, and some keywords that are common don’t have the same meaning.
1697
+ In particular, the branch management is very different and may cause confusion, especially when someone comes from Git’s universe.
1698
+ Nevertheless, it is possible to work on a Bazaar repository from a Git one.</p>
1699
+ </div>
1700
+ <div class="paragraph">
1701
+ <p>There are many projects that allow you to use Git as a Bazaar client.
1702
+ Here we’ll use Felipe Contreras' project that you may find at <a href="https://github.com/felipec/git-remote-bzr" class="bare">https://github.com/felipec/git-remote-bzr</a>.
1703
+ To install it, you just have to download the file git-remote-bzr in a folder contained in your <code>$PATH</code>:</p>
1704
+ </div>
1705
+ <div class="listingblock">
1706
+ <div class="content">
1707
+ <pre class="highlight"><code class="language-console" data-lang="console">$ wget https://raw.github.com/felipec/git-remote-bzr/master/git-remote-bzr -O ~/bin/git-remote-bzr
1708
+ $ chmod +x ~/bin/git-remote-bzr</code></pre>
1709
+ </div>
1710
+ </div>
1711
+ <div class="paragraph">
1712
+ <p>You also need to have Bazaar installed.
1713
+ That’s all!</p>
1714
+ </div>
1715
+ <div class="sect4">
1716
+ <h4 id="_create_a_git_repository_from_a_bazaar_repository">Create a Git repository from a Bazaar repository</h4>
1717
+ <div class="paragraph">
1718
+ <p>It is simple to use.
1719
+ It is enough to clone a Bazaar repository prefixing it by <code>bzr::</code>.
1720
+ Since Git and Bazaar both do full clones to your machine, it’s possible to attach a Git clone to your local Bazaar clone, but it isn’t recommended.
1721
+ It’s much easier to attach your Git clone directly to the same place your Bazaar clone is attached to — the central repository.</p>
1722
+ </div>
1723
+ <div class="paragraph">
1724
+ <p>Let’s suppose that you worked with a remote repository which is at address <code>bzr+ssh://developer@mybazaarserver:myproject</code>.
1725
+ Then you must clone it in the following way:</p>
1726
+ </div>
1727
+ <div class="listingblock">
1728
+ <div class="content">
1729
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git clone bzr::bzr+ssh://developer@mybazaarserver:myproject myProject-Git
1730
+ $ cd myProject-Git</code></pre>
1731
+ </div>
1732
+ </div>
1733
+ <div class="paragraph">
1734
+ <p>At this point, your Git repository is created but it is not compacted for optimal disk use.
1735
+ That’s why you should also clean and compact your Git repository, especially if it is a big one:</p>
1736
+ </div>
1737
+ <div class="listingblock">
1738
+ <div class="content">
1739
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git gc --aggressive</code></pre>
1740
+ </div>
1741
+ </div>
1742
+ </div>
1743
+ <div class="sect4">
1744
+ <h4 id="_bazaar_branches">Bazaar branches</h4>
1745
+ <div class="paragraph">
1746
+ <p>Bazaar only allows you to clone branches, but a repository may contain several branches, and <code>git-remote-bzr</code> can clone both.
1747
+ For example, to clone a branch:</p>
1748
+ </div>
1749
+ <div class="listingblock">
1750
+ <div class="content">
1751
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs/trunk emacs-trunk</code></pre>
1752
+ </div>
1753
+ </div>
1754
+ <div class="paragraph">
1755
+ <p>And to clone the whole repository:</p>
1756
+ </div>
1757
+ <div class="listingblock">
1758
+ <div class="content">
1759
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs emacs</code></pre>
1760
+ </div>
1761
+ </div>
1762
+ <div class="paragraph">
1763
+ <p>The second command clones all the branches contained in the emacs repository; nevertheless, it is possible to point out some branches:</p>
1764
+ </div>
1765
+ <div class="listingblock">
1766
+ <div class="content">
1767
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git config remote-bzr.branches 'trunk, xwindow'</code></pre>
1768
+ </div>
1769
+ </div>
1770
+ <div class="paragraph">
1771
+ <p>Some remote repositories don’t allow you to list their branches, in which case you have to manually specify them, and even though you could specify the configuration in the cloning command, you may find this easier:</p>
1772
+ </div>
1773
+ <div class="listingblock">
1774
+ <div class="content">
1775
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git init emacs
1776
+ $ git remote add origin bzr::bzr://bzr.savannah.gnu.org/emacs
1777
+ $ git config remote-bzr.branches 'trunk, xwindow'
1778
+ $ git fetch</code></pre>
1779
+ </div>
1780
+ </div>
1781
+ </div>
1782
+ <div class="sect4">
1783
+ <h4 id="_ignore_what_is_ignored_with_bzrignore">Ignore what is ignored with .bzrignore</h4>
1784
+ <div class="paragraph">
1785
+ <p>Since you are working on a project managed with Bazaar, you shouldn’t create a <code>.gitignore</code> file because you <em>may</em> accidentally set it under version control and the other people working with Bazaar would be disturbed.
1786
+ The solution is to create the <code>.git/info/exclude</code> file either as a symbolic link or as a regular file.
1787
+ We’ll see later on how to solve this question.</p>
1788
+ </div>
1789
+ <div class="paragraph">
1790
+ <p>Bazaar uses the same model as Git to ignore files, but also has two features which don’t have an equivalent into Git.
1791
+ The complete description may be found in <a href="http://doc.bazaar.canonical.com/bzr.2.7/en/user-reference/ignore-help.html">the documentation</a>.
1792
+ The two features are:</p>
1793
+ </div>
1794
+ <div class="olist arabic">
1795
+ <ol class="arabic">
1796
+ <li>
1797
+ <p>"!!" allows you to ignore certain file patterns even if they’re specified using a "!" rule.</p>
1798
+ </li>
1799
+ <li>
1800
+ <p>"RE:" at the beginning of a line allows you to specify a <a href="https://docs.python.org/3/library/re.html">Python regular expression</a> (Git only allows shell globs).</p>
1801
+ </li>
1802
+ </ol>
1803
+ </div>
1804
+ <div class="paragraph">
1805
+ <p>As a consequence, there are two different situations to consider:</p>
1806
+ </div>
1807
+ <div class="olist arabic">
1808
+ <ol class="arabic">
1809
+ <li>
1810
+ <p>If the <code>.bzrignore</code> file does not contain any of these two specific prefixes, then you can simply make a symbolic link to it in the repository: <code>ln -s .bzrignore .git/info/exclude</code>.</p>
1811
+ </li>
1812
+ <li>
1813
+ <p>Otherwise, you must create the <code>.git/info/exclude</code> file and adapt it to ignore exactly the same files in <code>.bzrignore</code>.</p>
1814
+ </li>
1815
+ </ol>
1816
+ </div>
1817
+ <div class="paragraph">
1818
+ <p>Whatever the case is, you will have to remain vigilant against any change of <code>.bzrignore</code> to make sure that the <code>.git/info/exclude</code> file always reflects <code>.bzrignore</code>.
1819
+ Indeed, if the <code>.bzrignore</code> file were to change and contained one or more lines starting with "!!" or "RE:", Git not being able to interpret these lines, you’ll have to adapt your <code>.git/info/exclude</code> file to ignore the same files as the ones ignored with <code>.bzrignore</code>.
1820
+ Moreover, if the <code>.git/info/exclude</code> file was a symbolic link, you’ll have to first delete the symbolic link, copy <code>.bzrignore</code> to <code>.git/info/exclude</code> and then adapt the latter.
1821
+ However, be careful with its creation because with Git it is impossible to re-include a file if a parent directory of that file is excluded.</p>
1822
+ </div>
1823
+ </div>
1824
+ <div class="sect4">
1825
+ <h4 id="_fetch_the_changes_of_the_remote_repository">Fetch the changes of the remote repository</h4>
1826
+ <div class="paragraph">
1827
+ <p>To fetch the changes of the remote, you pull changes as usually, using Git commands.
1828
+ Supposing that your changes are on the <code>master</code> branch, you merge or rebase your work on the <code>origin/master</code> branch:</p>
1829
+ </div>
1830
+ <div class="listingblock">
1831
+ <div class="content">
1832
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git pull --rebase origin</code></pre>
1833
+ </div>
1834
+ </div>
1835
+ </div>
1836
+ <div class="sect4">
1837
+ <h4 id="_push_your_work_on_the_remote_repository">Push your work on the remote repository</h4>
1838
+ <div class="paragraph">
1839
+ <p>Because Bazaar also has the concept of merge commits, there will be no problem if you push a merge commit.
1840
+ So you can work on a branch, merge the changes into <code>master</code> and push your work.
1841
+ Then, you create your branches, you test and commit your work as usual.
1842
+ You finally push your work to the Bazaar repository:</p>
1843
+ </div>
1844
+ <div class="listingblock">
1845
+ <div class="content">
1846
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin master</code></pre>
1847
+ </div>
1848
+ </div>
1849
+ </div>
1850
+ <div class="sect4">
1851
+ <h4 id="_caveats">Caveats</h4>
1852
+ <div class="paragraph">
1853
+ <p>Git’s remote-helpers framework has some limitations that apply.
1854
+ In particular, these commands don’t work:</p>
1855
+ </div>
1856
+ <div class="ulist">
1857
+ <ul>
1858
+ <li>
1859
+ <p>git push origin :branch-to-delete (Bazaar can’t accept ref deletions in this way)</p>
1860
+ </li>
1861
+ <li>
1862
+ <p>git push origin old:new (it will push <code>old</code>)</p>
1863
+ </li>
1864
+ <li>
1865
+ <p>git push --dry-run origin branch (it will push)</p>
1866
+ </li>
1867
+ </ul>
1868
+ </div>
1869
+ </div>
1870
+ <div class="sect4">
1871
+ <h4 id="_summary_11">Summary</h4>
1872
+ <div class="paragraph">
1873
+ <p>Since Git’s and Bazaar’s models are similar, there isn’t a lot of resistance when working across the boundary.
1874
+ As long as you watch out for the limitations, and are always aware that the remote repository isn’t natively Git, you’ll be fine.</p>
1875
+ </div>
1876
+ </div>
1877
+ </div>
1878
+ <div class="sect3">
1879
+ <h3 id="_git_and_perforce">Git and Perforce</h3>
1880
+ <div class="paragraph">
1881
+ <p>
1882
+
1883
+ Perforce is a very popular version-control system in corporate environments.
1884
+ It’s been around since 1995, which makes it the oldest system covered in this chapter.
1885
+ As such, it’s designed with the constraints of its day; it assumes you’re always connected to a single central server, and only one version is kept on the local disk.
1886
+ To be sure, its features and constraints are well-suited to several specific problems, but there are lots of projects using Perforce where Git would actually work better.</p>
1887
+ </div>
1888
+ <div class="paragraph">
1889
+ <p>There are two options if you’d like to mix your use of Perforce and Git.
1890
+ The first one we’ll cover is the “Git Fusion” bridge from the makers of Perforce, which lets you expose subtrees of your Perforce depot as read-write Git repositories.
1891
+ The second is git-p4, a client-side bridge that lets you use Git as a Perforce client, without requiring any reconfiguration of the Perforce server.</p>
1892
+ </div>
1893
+ <div class="sect4">
1894
+ <h4 id="_p4_git_fusion">Git Fusion</h4>
1895
+ <div class="paragraph">
1896
+ <p>
1897
+ Perforce provides a product called Git Fusion (available at <a href="http://www.perforce.com/git-fusion" class="bare">http://www.perforce.com/git-fusion</a>), which synchronizes a Perforce server with Git repositories on the server side.</p>
1898
+ </div>
1899
+ <div class="sect5">
1900
+ <h6 id="_setting_up_2">Setting Up</h6>
1901
+ <div class="paragraph">
1902
+ <p>For our examples, we’ll be using the easiest installation method for Git Fusion, which is downloading a virtual machine that runs the Perforce daemon and Git Fusion.
1903
+ You can get the virtual machine image from <a href="http://www.perforce.com/downloads/Perforce/20-User" class="bare">http://www.perforce.com/downloads/Perforce/20-User</a>, and once it’s finished downloading, import it into your favorite virtualization software (we’ll use VirtualBox).</p>
1904
+ </div>
1905
+ <div class="paragraph">
1906
+ <p>Upon first starting the machine, it asks you to customize the password for three Linux users (<code>root</code>, <code>perforce</code>, and <code>git</code>), and provide an instance name, which can be used to distinguish this installation from others on the same network.
1907
+ When that has all completed, you’ll see this:</p>
1908
+ </div>
1909
+ <div class="imageblock">
1910
+ <div class="content">
1911
+ <img src="images/git-fusion-boot.png" alt="The Git Fusion virtual machine boot screen">
1912
+ </div>
1913
+ <div class="title">Figure 145. The Git Fusion virtual machine boot screen</div>
1914
+ </div>
1915
+ <div class="paragraph">
1916
+ <p>You should take note of the IP address that’s shown here, we’ll be using it later on.
1917
+ Next, we’ll create a Perforce user.
1918
+ Select the “Login” option at the bottom and press enter (or SSH to the machine), and log in as <code>root</code>.
1919
+ Then use these commands to create a user:</p>
1920
+ </div>
1921
+ <div class="listingblock">
1922
+ <div class="content">
1923
+ <pre class="highlight"><code class="language-console" data-lang="console">$ p4 -p localhost:1666 -u super user -f john
1924
+ $ p4 -p localhost:1666 -u john passwd
1925
+ $ exit</code></pre>
1926
+ </div>
1927
+ </div>
1928
+ <div class="paragraph">
1929
+ <p>The first one will open a VI editor to customize the user, but you can accept the defaults by typing <code>:wq</code> and hitting enter.
1930
+ The second one will prompt you to enter a password twice.
1931
+ That’s all we need to do with a shell prompt, so exit out of the session.</p>
1932
+ </div>
1933
+ <div class="paragraph">
1934
+ <p>The next thing you’ll need to do to follow along is to tell Git not to verify SSL certificates.
1935
+ The Git Fusion image comes with a certificate, but it’s for a domain that won’t match your virtual machine’s IP address, so Git will reject the HTTPS connection.
1936
+ If this is going to be a permanent installation, consult the Perforce Git Fusion manual to install a different certificate; for our example purposes, this will suffice:</p>
1937
+ </div>
1938
+ <div class="listingblock">
1939
+ <div class="content">
1940
+ <pre class="highlight"><code class="language-console" data-lang="console">$ export GIT_SSL_NO_VERIFY=true</code></pre>
1941
+ </div>
1942
+ </div>
1943
+ <div class="paragraph">
1944
+ <p>Now we can test that everything is working.</p>
1945
+ </div>
1946
+ <div class="listingblock">
1947
+ <div class="content">
1948
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git clone https://10.0.1.254/Talkhouse
1949
+ Cloning into 'Talkhouse'...
1950
+ Username for 'https://10.0.1.254': john
1951
+ Password for 'https://john@10.0.1.254':
1952
+ remote: Counting objects: 630, done.
1953
+ remote: Compressing objects: 100% (581/581), done.
1954
+ remote: Total 630 (delta 172), reused 0 (delta 0)
1955
+ Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done.
1956
+ Resolving deltas: 100% (172/172), done.
1957
+ Checking connectivity... done.</code></pre>
1958
+ </div>
1959
+ </div>
1960
+ <div class="paragraph">
1961
+ <p>The virtual-machine image comes equipped with a sample project that you can clone.
1962
+ Here we’re cloning over HTTPS, with the <code>john</code> user that we created above; Git asks for credentials for this connection, but the credential cache will allow us to skip this step for any subsequent requests.</p>
1963
+ </div>
1964
+ </div>
1965
+ <div class="sect5">
1966
+ <h6 id="_fusion_configuration">Fusion Configuration</h6>
1967
+ <div class="paragraph">
1968
+ <p>Once you’ve got Git Fusion installed, you’ll want to tweak the configuration.
1969
+ This is actually fairly easy to do using your favorite Perforce client; just map the <code>//.git-fusion</code> directory on the Perforce server into your workspace.
1970
+ The file structure looks like this:</p>
1971
+ </div>
1972
+ <div class="listingblock">
1973
+ <div class="content">
1974
+ <pre class="highlight"><code class="language-console" data-lang="console">$ tree
1975
+ .
1976
+ ├── objects
1977
+ │   ├── repos
1978
+ │   │   └── [...]
1979
+ │   └── trees
1980
+ │   └── [...]
1981
+
1982
+ ├── p4gf_config
1983
+ ├── repos
1984
+ │   └── Talkhouse
1985
+ │   └── p4gf_config
1986
+ └── users
1987
+ └── p4gf_usermap
1988
+
1989
+ 498 directories, 287 files</code></pre>
1990
+ </div>
1991
+ </div>
1992
+ <div class="paragraph">
1993
+ <p>The <code>objects</code> directory is used internally by Git Fusion to map Perforce objects to Git and vice versa, you won’t have to mess with anything in there.
1994
+ There’s a global <code>p4gf_config</code> file in this directory, as well as one for each repository – these are the configuration files that determine how Git Fusion behaves.
1995
+ Let’s take a look at the file in the root:</p>
1996
+ </div>
1997
+ <div class="listingblock">
1998
+ <div class="content">
1999
+ <pre class="highlight"><code class="language-ini" data-lang="ini">[repo-creation]
2000
+ charset = utf8
2001
+
2002
+ [git-to-perforce]
2003
+ change-owner = author
2004
+ enable-git-branch-creation = yes
2005
+ enable-swarm-reviews = yes
2006
+ enable-git-merge-commits = yes
2007
+ enable-git-submodules = yes
2008
+ preflight-commit = none
2009
+ ignore-author-permissions = no
2010
+ read-permission-check = none
2011
+ git-merge-avoidance-after-change-num = 12107
2012
+
2013
+ [perforce-to-git]
2014
+ http-url = none
2015
+ ssh-url = none
2016
+
2017
+ [@features]
2018
+ imports = False
2019
+ chunked-push = False
2020
+ matrix2 = False
2021
+ parallel-push = False
2022
+
2023
+ [authentication]
2024
+ email-case-sensitivity = no</code></pre>
2025
+ </div>
2026
+ </div>
2027
+ <div class="paragraph">
2028
+ <p>We won’t go into the meanings of these flags here, but note that this is just an INI-formatted text file, much like Git uses for configuration.
2029
+ This file specifies the global options, which can then be overridden by repository-specific configuration files, like <code>repos/Talkhouse/p4gf_config</code>.
2030
+ If you open this file, you’ll see a <code>[@repo]</code> section with some settings that are different from the global defaults.
2031
+ You’ll also see sections that look like this:</p>
2032
+ </div>
2033
+ <div class="listingblock">
2034
+ <div class="content">
2035
+ <pre class="highlight"><code class="language-ini" data-lang="ini">[Talkhouse-master]
2036
+ git-branch-name = master
2037
+ view = //depot/Talkhouse/main-dev/... ...</code></pre>
2038
+ </div>
2039
+ </div>
2040
+ <div class="paragraph">
2041
+ <p>This is a mapping between a Perforce branch and a Git branch.
2042
+ The section can be named whatever you like, so long as the name is unique.
2043
+ <code>git-branch-name</code> lets you convert a depot path that would be cumbersome under Git to a more friendly name.
2044
+ The <code>view</code> setting controls how Perforce files are mapped into the Git repository, using the standard view mapping syntax.
2045
+ More than one mapping can be specified, like in this example:</p>
2046
+ </div>
2047
+ <div class="listingblock">
2048
+ <div class="content">
2049
+ <pre class="highlight"><code class="language-ini" data-lang="ini">[multi-project-mapping]
2050
+ git-branch-name = master
2051
+ view = //depot/project1/main/... project1/...
2052
+ //depot/project2/mainline/... project2/...</code></pre>
2053
+ </div>
2054
+ </div>
2055
+ <div class="paragraph">
2056
+ <p>This way, if your normal workspace mapping includes changes in the structure of the directories, you can replicate that with a Git repository.</p>
2057
+ </div>
2058
+ <div class="paragraph">
2059
+ <p>The last file we’ll discuss is <code>users/p4gf_usermap</code>, which maps Perforce users to Git users, and which you may not even need.
2060
+ When converting from a Perforce changeset to a Git commit, Git Fusion’s default behavior is to look up the Perforce user, and use the email address and full name stored there for the author/committer field in Git.
2061
+ When converting the other way, the default is to look up the Perforce user with the email address stored in the Git commit’s author field, and submit the changeset as that user (with permissions applying).
2062
+ In most cases, this behavior will do just fine, but consider the following mapping file:</p>
2063
+ </div>
2064
+ <div class="listingblock">
2065
+ <div class="content">
2066
+ <pre class="highlight"><code>john john@example.com "John Doe"
2067
+ john johnny@appleseed.net "John Doe"
2068
+ bob employeeX@example.com "Anon X. Mouse"
2069
+ joe employeeY@example.com "Anon Y. Mouse"</code></pre>
2070
+ </div>
2071
+ </div>
2072
+ <div class="paragraph">
2073
+ <p>Each line is of the format <code>&lt;user&gt; &lt;email&gt; "&lt;full name&gt;"</code>, and creates a single user mapping.
2074
+ The first two lines map two distinct email addresses to the same Perforce user account.
2075
+ This is useful if you’ve created Git commits under several different email addresses (or change email addresses), but want them to be mapped to the same Perforce user.
2076
+ When creating a Git commit from a Perforce changeset, the first line matching the Perforce user is used for Git authorship information.</p>
2077
+ </div>
2078
+ <div class="paragraph">
2079
+ <p>The last two lines mask Bob and Joe’s actual names and email addresses from the Git commits that are created.
2080
+ This is nice if you want to open-source an internal project, but don’t want to publish your employee directory to the entire world.
2081
+ Note that the email addresses and full names should be unique, unless you want all the Git commits to be attributed to a single fictional author.</p>
2082
+ </div>
2083
+ </div>
2084
+ <div class="sect5">
2085
+ <h6 id="_workflow_2">Workflow</h6>
2086
+ <div class="paragraph">
2087
+ <p>Perforce Git Fusion is a two-way bridge between Perforce and Git version control.
2088
+ Let’s have a look at how it feels to work from the Git side.
2089
+ We’ll assume we’ve mapped in the “Jam” project using a configuration file as shown above, which we can clone like this:</p>
2090
+ </div>
2091
+ <div class="listingblock">
2092
+ <div class="content">
2093
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git clone https://10.0.1.254/Jam
2094
+ Cloning into 'Jam'...
2095
+ Username for 'https://10.0.1.254': john
2096
+ Password for 'https://john@10.0.1.254':
2097
+ remote: Counting objects: 2070, done.
2098
+ remote: Compressing objects: 100% (1704/1704), done.
2099
+ Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done.
2100
+ remote: Total 2070 (delta 1242), reused 0 (delta 0)
2101
+ Resolving deltas: 100% (1242/1242), done.
2102
+ Checking connectivity... done.
2103
+ $ git branch -a
2104
+ * master
2105
+ remotes/origin/HEAD -&gt; origin/master
2106
+ remotes/origin/master
2107
+ remotes/origin/rel2.1
2108
+ $ git log --oneline --decorate --graph --all
2109
+ * 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch.
2110
+ | * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest metrowerks on Beos -- the Intel one.
2111
+ | * bd2f54a Put in fix for jam's NT handle leak.
2112
+ | * c0f29e7 Fix URL in a jam doc
2113
+ | * cc644ac Radstone's lynx port.
2114
+ [...]</code></pre>
2115
+ </div>
2116
+ </div>
2117
+ <div class="paragraph">
2118
+ <p>The first time you do this, it may take some time.
2119
+ What’s happening is that Git Fusion is converting all the applicable changesets in the Perforce history into Git commits.
2120
+ This happens locally on the server, so it’s relatively fast, but if you have a lot of history, it can still take some time.
2121
+ Subsequent fetches do incremental conversion, so it’ll feel more like Git’s native speed.</p>
2122
+ </div>
2123
+ <div class="paragraph">
2124
+ <p>As you can see, our repository looks exactly like any other Git repository you might work with.
2125
+ There are three branches, and Git has helpfully created a local <code>master</code> branch that tracks <code>origin/master</code>.
2126
+ Let’s do a bit of work, and create a couple of new commits:</p>
2127
+ </div>
2128
+ <div class="listingblock">
2129
+ <div class="content">
2130
+ <pre class="highlight"><code class="language-console" data-lang="console"># ...
2131
+ $ git log --oneline --decorate --graph --all
2132
+ * cfd46ab (HEAD, master) Add documentation for new feature
2133
+ * a730d77 Whitespace
2134
+ * d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on Beos -- the Intel one.
2135
+ * bd2f54a Put in fix for jam's NT handle leak.
2136
+ [...]</code></pre>
2137
+ </div>
2138
+ </div>
2139
+ <div class="paragraph">
2140
+ <p>We have two new commits.
2141
+ Now let’s check if anyone else has been working:</p>
2142
+ </div>
2143
+ <div class="listingblock">
2144
+ <div class="content">
2145
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch
2146
+ remote: Counting objects: 5, done.
2147
+ remote: Compressing objects: 100% (3/3), done.
2148
+ remote: Total 3 (delta 2), reused 0 (delta 0)
2149
+ Unpacking objects: 100% (3/3), done.
2150
+ From https://10.0.1.254/Jam
2151
+ d254865..6afeb15 master -&gt; origin/master
2152
+ $ git log --oneline --decorate --graph --all
2153
+ * 6afeb15 (origin/master, origin/HEAD) Update copyright
2154
+ | * cfd46ab (HEAD, master) Add documentation for new feature
2155
+ | * a730d77 Whitespace
2156
+ |/
2157
+ * d254865 Upgrade to latest metrowerks on Beos -- the Intel one.
2158
+ * bd2f54a Put in fix for jam's NT handle leak.
2159
+ [...]</code></pre>
2160
+ </div>
2161
+ </div>
2162
+ <div class="paragraph">
2163
+ <p>It looks like someone was!
2164
+ You wouldn’t know it from this view, but the <code>6afeb15</code> commit was actually created using a Perforce client.
2165
+ It just looks like another commit from Git’s point of view, which is exactly the point.
2166
+ Let’s see how the Perforce server deals with a merge commit:</p>
2167
+ </div>
2168
+ <div class="listingblock">
2169
+ <div class="content">
2170
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master
2171
+ Auto-merging README
2172
+ Merge made by the 'recursive' strategy.
2173
+ README | 2 +-
2174
+ 1 file changed, 1 insertion(+), 1 deletion(-)
2175
+ $ git push
2176
+ Counting objects: 9, done.
2177
+ Delta compression using up to 8 threads.
2178
+ Compressing objects: 100% (9/9), done.
2179
+ Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
2180
+ Total 9 (delta 6), reused 0 (delta 0)
2181
+ remote: Perforce: 100% (3/3) Loading commit tree into memory...
2182
+ remote: Perforce: 100% (5/5) Finding child commits...
2183
+ remote: Perforce: Running git fast-export...
2184
+ remote: Perforce: 100% (3/3) Checking commits...
2185
+ remote: Processing will continue even if connection is closed.
2186
+ remote: Perforce: 100% (3/3) Copying changelists...
2187
+ remote: Perforce: Submitting new Git commit objects to Perforce: 4
2188
+ To https://10.0.1.254/Jam
2189
+ 6afeb15..89cba2b master -&gt; master</code></pre>
2190
+ </div>
2191
+ </div>
2192
+ <div class="paragraph">
2193
+ <p>Git thinks it worked.
2194
+ Let’s take a look at the history of the <code>README</code> file from Perforce’s point of view, using the revision graph feature of <code>p4v</code>:</p>
2195
+ </div>
2196
+ <div class="imageblock">
2197
+ <div class="content">
2198
+ <img src="images/git-fusion-perforce-graph.png" alt="Perforce revision graph resulting from Git push">
2199
+ </div>
2200
+ <div class="title">Figure 146. Perforce revision graph resulting from Git push</div>
2201
+ </div>
2202
+ <div class="paragraph">
2203
+ <p>If you’ve never seen this view before, it may seem confusing, but it shows the same concepts as a graphical viewer for Git history.
2204
+ We’re looking at the history of the <code>README</code> file, so the directory tree at top left only shows that file as it surfaces in various branches.
2205
+ At top right, we have a visual graph of how different revisions of the file are related, and the big-picture view of this graph is at bottom right.
2206
+ The rest of the view is given to the details view for the selected revision (<code>2</code> in this case).</p>
2207
+ </div>
2208
+ <div class="paragraph">
2209
+ <p>One thing to notice is that the graph looks exactly like the one in Git’s history.
2210
+ Perforce didn’t have a named branch to store the <code>1</code> and <code>2</code> commits, so it made an “anonymous” branch in the <code>.git-fusion</code> directory to hold it.
2211
+ This will also happen for named Git branches that don’t correspond to a named Perforce branch (and you can later map them to a Perforce branch using the configuration file).</p>
2212
+ </div>
2213
+ <div class="paragraph">
2214
+ <p>Most of this happens behind the scenes, but the end result is that one person on a team can be using Git, another can be using Perforce, and neither of them will know about the other’s choice.</p>
2215
+ </div>
2216
+ </div>
2217
+ <div class="sect5">
2218
+ <h6 id="_git_fusion_summary">Git-Fusion Summary</h6>
2219
+ <div class="paragraph">
2220
+ <p>If you have (or can get) access to your Perforce server, Git Fusion is a great way to make Git and Perforce talk to each other.
2221
+ There’s a bit of configuration involved, but the learning curve isn’t very steep.
2222
+ This is one of the few sections in this chapter where cautions about using Git’s full power will not appear.
2223
+ That’s not to say that Perforce will be happy with everything you throw at it – if you try to rewrite history that’s already been pushed, Git Fusion will reject it – but Git Fusion tries very hard to feel native.
2224
+ You can even use Git submodules (though they’ll look strange to Perforce users), and merge branches (this will be recorded as an integration on the Perforce side).</p>
2225
+ </div>
2226
+ <div class="paragraph">
2227
+ <p>If you can’t convince the administrator of your server to set up Git Fusion, there is still a way to use these tools together.</p>
2228
+ </div>
2229
+ </div>
2230
+ </div>
2231
+ <div class="sect4">
2232
+ <h4 id="_git_p4_client">Git-p4</h4>
2233
+ <div class="paragraph">
2234
+ <p>
2235
+ Git-p4 is a two-way bridge between Git and Perforce.
2236
+ It runs entirely inside your Git repository, so you won’t need any kind of access to the Perforce server (other than user credentials, of course).
2237
+ Git-p4 isn’t as flexible or complete a solution as Git Fusion, but it does allow you to do most of what you’d want to do without being invasive to the server environment.</p>
2238
+ </div>
2239
+ <div class="admonitionblock note">
2240
+ <table>
2241
+ <tr>
2242
+ <td class="icon">
2243
+ <div class="title">Note</div>
2244
+ </td>
2245
+ <td class="content">
2246
+ <div class="paragraph">
2247
+ <p>You’ll need the <code>p4</code> tool somewhere in your <code>PATH</code> to work with git-p4.
2248
+ As of this writing, it is freely available at <a href="http://www.perforce.com/downloads/Perforce/20-User" class="bare">http://www.perforce.com/downloads/Perforce/20-User</a>.</p>
2249
+ </div>
2250
+ </td>
2251
+ </tr>
2252
+ </table>
2253
+ </div>
2254
+ <div class="sect5">
2255
+ <h6 id="_setting_up_3">Setting Up</h6>
2256
+ <div class="paragraph">
2257
+ <p>For example purposes, we’ll be running the Perforce server from the Git Fusion OVA as shown above, but we’ll bypass the Git Fusion server and go directly to the Perforce version control.</p>
2258
+ </div>
2259
+ <div class="paragraph">
2260
+ <p>In order to use the <code>p4</code> command-line client (which git-p4 depends on), you’ll need to set a couple of environment variables:</p>
2261
+ </div>
2262
+ <div class="listingblock">
2263
+ <div class="content">
2264
+ <pre class="highlight"><code class="language-console" data-lang="console">$ export P4PORT=10.0.1.254:1666
2265
+ $ export P4USER=john</code></pre>
2266
+ </div>
2267
+ </div>
2268
+ </div>
2269
+ <div class="sect5">
2270
+ <h6 id="_getting_started_3">Getting Started</h6>
2271
+ <div class="paragraph">
2272
+ <p>As with anything in Git, the first command is to clone:</p>
2273
+ </div>
2274
+ <div class="listingblock">
2275
+ <div class="content">
2276
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 clone //depot/www/live www-shallow
2277
+ Importing from //depot/www/live into www-shallow
2278
+ Initialized empty Git repository in /private/tmp/www-shallow/.git/
2279
+ Doing initial import of //depot/www/live/ from revision #head into refs/remotes/p4/master</code></pre>
2280
+ </div>
2281
+ </div>
2282
+ <div class="paragraph">
2283
+ <p>This creates what in Git terms is a “shallow” clone; only the very latest Perforce revision is imported into Git; remember, Perforce isn’t designed to give every revision to every user.
2284
+ This is enough to use Git as a Perforce client, but for other purposes it’s not enough.</p>
2285
+ </div>
2286
+ <div class="paragraph">
2287
+ <p>Once it’s finished, we have a fully-functional Git repository:</p>
2288
+ </div>
2289
+ <div class="listingblock">
2290
+ <div class="content">
2291
+ <pre class="highlight"><code class="language-console" data-lang="console">$ cd myproject
2292
+ $ git log --oneline --all --graph --decorate
2293
+ * 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of //depot/www/live/ from the state at revision #head</code></pre>
2294
+ </div>
2295
+ </div>
2296
+ <div class="paragraph">
2297
+ <p>Note how there’s a “p4” remote for the Perforce server, but everything else looks like a standard clone.
2298
+ Actually, that’s a bit misleading; there isn’t actually a remote there.</p>
2299
+ </div>
2300
+ <div class="listingblock">
2301
+ <div class="content">
2302
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git remote -v</code></pre>
2303
+ </div>
2304
+ </div>
2305
+ <div class="paragraph">
2306
+ <p>No remotes exist in this repository at all.
2307
+ Git-p4 has created some refs to represent the state of the server, and they look like remote refs to <code>git log</code>, but they’re not managed by Git itself, and you can’t push to them.</p>
2308
+ </div>
2309
+ </div>
2310
+ <div class="sect5">
2311
+ <h6 id="_workflow_3">Workflow</h6>
2312
+ <div class="paragraph">
2313
+ <p>Okay, let’s do some work.
2314
+ Let’s assume you’ve made some progress on a very important feature, and you’re ready to show it to the rest of your team.</p>
2315
+ </div>
2316
+ <div class="listingblock">
2317
+ <div class="content">
2318
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git log --oneline --all --graph --decorate
2319
+ * 018467c (HEAD, master) Change page title
2320
+ * c0fb617 Update link
2321
+ * 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from the state at revision #head</code></pre>
2322
+ </div>
2323
+ </div>
2324
+ <div class="paragraph">
2325
+ <p>We’ve made two new commits that we’re ready to submit to the Perforce server.
2326
+ Let’s check if anyone else was working today:</p>
2327
+ </div>
2328
+ <div class="listingblock">
2329
+ <div class="content">
2330
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 sync
2331
+ git p4 sync
2332
+ Performing incremental import into refs/remotes/p4/master git branch
2333
+ Depot paths: //depot/www/live/
2334
+ Import destination: refs/remotes/p4/master
2335
+ Importing revision 12142 (100%)
2336
+ $ git log --oneline --all --graph --decorate
2337
+ * 75cd059 (p4/master, p4/HEAD) Update copyright
2338
+ | * 018467c (HEAD, master) Change page title
2339
+ | * c0fb617 Update link
2340
+ |/
2341
+ * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre>
2342
+ </div>
2343
+ </div>
2344
+ <div class="paragraph">
2345
+ <p>Looks like they were, and <code>master</code> and <code>p4/master</code> have diverged.
2346
+ Perforce’s branching system is <em>nothing</em> like Git’s, so submitting merge commits doesn’t make any sense.
2347
+ Git-p4 recommends that you rebase your commits, and even comes with a shortcut to do so:</p>
2348
+ </div>
2349
+ <div class="listingblock">
2350
+ <div class="content">
2351
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 rebase
2352
+ Performing incremental import into refs/remotes/p4/master git branch
2353
+ Depot paths: //depot/www/live/
2354
+ No changes to import!
2355
+ Rebasing the current branch onto remotes/p4/master
2356
+ First, rewinding head to replay your work on top of it...
2357
+ Applying: Update link
2358
+ Applying: Change page title
2359
+ index.html | 2 +-
2360
+ 1 file changed, 1 insertion(+), 1 deletion(-)</code></pre>
2361
+ </div>
2362
+ </div>
2363
+ <div class="paragraph">
2364
+ <p>You can probably tell from the output, but <code>git p4 rebase</code> is a shortcut for <code>git p4 sync</code> followed by <code>git rebase p4/master</code>.
2365
+ It’s a bit smarter than that, especially when working with multiple branches, but this is a good approximation.</p>
2366
+ </div>
2367
+ <div class="paragraph">
2368
+ <p>Now our history is linear again, and we’re ready to contribute our changes back to Perforce.
2369
+ The <code>git p4 submit</code> command will try to create a new Perforce revision for every Git commit between <code>p4/master</code> and <code>master</code>.
2370
+ Running it drops us into our favorite editor, and the contents of the file look something like this:</p>
2371
+ </div>
2372
+ <div class="listingblock">
2373
+ <div class="content">
2374
+ <pre class="highlight"><code class="language-console" data-lang="console"># A Perforce Change Specification.
2375
+ #
2376
+ # Change: The change number. 'new' on a new changelist.
2377
+ # Date: The date this specification was last modified.
2378
+ # Client: The client on which the changelist was created. Read-only.
2379
+ # User: The user who created the changelist.
2380
+ # Status: Either 'pending' or 'submitted'. Read-only.
2381
+ # Type: Either 'public' or 'restricted'. Default is 'public'.
2382
+ # Description: Comments about the changelist. Required.
2383
+ # Jobs: What opened jobs are to be closed by this changelist.
2384
+ # You may delete jobs from this list. (New changelists only.)
2385
+ # Files: What opened files from the default changelist are to be added
2386
+ # to this changelist. You may delete files from this list.
2387
+ # (New changelists only.)
2388
+
2389
+ Change: new
2390
+
2391
+ Client: john_bens-mbp_8487
2392
+
2393
+ User: john
2394
+
2395
+ Status: new
2396
+
2397
+ Description:
2398
+ Update link
2399
+
2400
+ Files:
2401
+ //depot/www/live/index.html # edit
2402
+
2403
+
2404
+ ######## git author ben@straub.cc does not match your p4 account.
2405
+ ######## Use option --preserve-user to modify authorship.
2406
+ ######## Variable git-p4.skipUserNameCheck hides this message.
2407
+ ######## everything below this line is just the diff #######
2408
+ --- //depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000
2409
+ +++ /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000
2410
+ @@ -60,7 +60,7 @@
2411
+ &lt;/td&gt;
2412
+ &lt;td valign=top&gt;
2413
+ Source and documentation for
2414
+ -&lt;a href="http://www.perforce.com/jam/jam.html"&gt;
2415
+ +&lt;a href="jam.html"&gt;
2416
+ Jam/MR&lt;/a&gt;,
2417
+ a software build tool.
2418
+ &lt;/td&gt;</code></pre>
2419
+ </div>
2420
+ </div>
2421
+ <div class="paragraph">
2422
+ <p>This is mostly the same content you’d see by running <code>p4 submit</code>, except the stuff at the end which git-p4 has helpfully included.
2423
+ Git-p4 tries to honor your Git and Perforce settings individually when it has to provide a name for a commit or changeset, but in some cases you want to override it.
2424
+ For example, if the Git commit you’re importing was written by a contributor who doesn’t have a Perforce user account, you may still want the resulting changeset to look like they wrote it (and not you).</p>
2425
+ </div>
2426
+ <div class="paragraph">
2427
+ <p>Git-p4 has helpfully imported the message from the Git commit as the content for this Perforce changeset, so all we have to do is save and quit, twice (once for each commit).
2428
+ The resulting shell output will look something like this:</p>
2429
+ </div>
2430
+ <div class="listingblock">
2431
+ <div class="content">
2432
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 submit
2433
+ Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
2434
+ Synchronizing p4 checkout...
2435
+ ... - file(s) up-to-date.
2436
+ Applying dbac45b Update link
2437
+ //depot/www/live/index.html#4 - opened for edit
2438
+ Change 12143 created with 1 open file(s).
2439
+ Submitting change 12143.
2440
+ Locking 1 files ...
2441
+ edit //depot/www/live/index.html#5
2442
+ Change 12143 submitted.
2443
+ Applying 905ec6a Change page title
2444
+ //depot/www/live/index.html#5 - opened for edit
2445
+ Change 12144 created with 1 open file(s).
2446
+ Submitting change 12144.
2447
+ Locking 1 files ...
2448
+ edit //depot/www/live/index.html#6
2449
+ Change 12144 submitted.
2450
+ All commits applied!
2451
+ Performing incremental import into refs/remotes/p4/master git branch
2452
+ Depot paths: //depot/www/live/
2453
+ Import destination: refs/remotes/p4/master
2454
+ Importing revision 12144 (100%)
2455
+ Rebasing the current branch onto remotes/p4/master
2456
+ First, rewinding head to replay your work on top of it...
2457
+ $ git log --oneline --all --graph --decorate
2458
+ * 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title
2459
+ * 05f1ade Update link
2460
+ * 75cd059 Update copyright
2461
+ * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre>
2462
+ </div>
2463
+ </div>
2464
+ <div class="paragraph">
2465
+ <p>The result is as though we just did a <code>git push</code>, which is the closest analogy to what actually did happen.</p>
2466
+ </div>
2467
+ <div class="paragraph">
2468
+ <p>Note that during this process every Git commit is turned into a Perforce changeset; if you want to squash them down into a single changeset, you can do that with an interactive rebase before running <code>git p4 submit</code>.
2469
+ Also note that the SHA-1 hashes of all the commits that were submitted as changesets have changed; this is because git-p4 adds a line to the end of each commit it converts:</p>
2470
+ </div>
2471
+ <div class="listingblock">
2472
+ <div class="content">
2473
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git log -1
2474
+ commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145
2475
+ Author: John Doe &lt;john@example.com&gt;
2476
+ Date: Sun Aug 31 10:31:44 2014 -0800
2477
+
2478
+ Change page title
2479
+
2480
+ [git-p4: depot-paths = "//depot/www/live/": change = 12144]</code></pre>
2481
+ </div>
2482
+ </div>
2483
+ <div class="paragraph">
2484
+ <p>What happens if you try to submit a merge commit?
2485
+ Let’s give it a try.
2486
+ Here’s the situation we’ve gotten ourselves into:</p>
2487
+ </div>
2488
+ <div class="listingblock">
2489
+ <div class="content">
2490
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git log --oneline --all --graph --decorate
2491
+ * 3be6fd8 (HEAD, master) Correct email address
2492
+ * 1dcbf21 Merge remote-tracking branch 'p4/master'
2493
+ |\
2494
+ | * c4689fc (p4/master, p4/HEAD) Grammar fix
2495
+ * | cbacd0a Table borders: yes please
2496
+ * | b4959b6 Trademark
2497
+ |/
2498
+ * 775a46f Change page title
2499
+ * 05f1ade Update link
2500
+ * 75cd059 Update copyright
2501
+ * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre>
2502
+ </div>
2503
+ </div>
2504
+ <div class="paragraph">
2505
+ <p>The Git and Perforce history diverge after 775a46f.
2506
+ The Git side has two commits, then a merge commit with the Perforce head, then another commit.
2507
+ We’re going to try to submit these on top of a single changeset on the Perforce side.
2508
+ Let’s see what would happen if we tried to submit now:</p>
2509
+ </div>
2510
+ <div class="listingblock">
2511
+ <div class="content">
2512
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 submit -n
2513
+ Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
2514
+ Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
2515
+ Would apply
2516
+ b4959b6 Trademark
2517
+ cbacd0a Table borders: yes please
2518
+ 3be6fd8 Correct email address</code></pre>
2519
+ </div>
2520
+ </div>
2521
+ <div class="paragraph">
2522
+ <p>The <code>-n</code> flag is short for <code>--dry-run</code>, which tries to report what would happen if the submit command were run for real.
2523
+ In this case, it looks like we’d be creating three Perforce changesets, which correspond to the three non-merge commits that don’t yet exist on the Perforce server.
2524
+ That sounds like exactly what we want, let’s see how it turns out:</p>
2525
+ </div>
2526
+ <div class="listingblock">
2527
+ <div class="content">
2528
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 submit
2529
+ […]
2530
+ $ git log --oneline --all --graph --decorate
2531
+ * dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address
2532
+ * 1b79a80 Table borders: yes please
2533
+ * 0097235 Trademark
2534
+ * c4689fc Grammar fix
2535
+ * 775a46f Change page title
2536
+ * 05f1ade Update link
2537
+ * 75cd059 Update copyright
2538
+ * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre>
2539
+ </div>
2540
+ </div>
2541
+ <div class="paragraph">
2542
+ <p>Our history became linear, just as though we had rebased before submitting (which is in fact exactly what happened).
2543
+ This means you can be free to create, work on, throw away, and merge branches on the Git side without fear that your history will somehow become incompatible with Perforce.
2544
+ If you can rebase it, you can contribute it to a Perforce server.</p>
2545
+ </div>
2546
+ </div>
2547
+ <div class="sect5">
2548
+ <h6 id="_git_p4_branches">Branching</h6>
2549
+ <div class="paragraph">
2550
+ <p>If your Perforce project has multiple branches, you’re not out of luck; git-p4 can handle that in a way that makes it feel like Git.
2551
+ Let’s say your Perforce depot is laid out like this:</p>
2552
+ </div>
2553
+ <div class="listingblock">
2554
+ <div class="content">
2555
+ <pre class="highlight"><code>//depot
2556
+ └── project
2557
+ ├── main
2558
+ └── dev</code></pre>
2559
+ </div>
2560
+ </div>
2561
+ <div class="paragraph">
2562
+ <p>And let’s say you have a <code>dev</code> branch, which has a view spec that looks like this:</p>
2563
+ </div>
2564
+ <div class="listingblock">
2565
+ <div class="content">
2566
+ <pre class="highlight"><code>//depot/project/main/... //depot/project/dev/...</code></pre>
2567
+ </div>
2568
+ </div>
2569
+ <div class="paragraph">
2570
+ <p>Git-p4 can automatically detect that situation and do the right thing:</p>
2571
+ </div>
2572
+ <div class="listingblock">
2573
+ <div class="content">
2574
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 clone --detect-branches //depot/project@all
2575
+ Importing from //depot/project@all into project
2576
+ Initialized empty Git repository in /private/tmp/project/.git/
2577
+ Importing revision 20 (50%)
2578
+ Importing new branch project/dev
2579
+
2580
+ Resuming with change 20
2581
+ Importing revision 22 (100%)
2582
+ Updated branches: main dev
2583
+ $ cd project; git log --oneline --all --graph --decorate
2584
+ * eae77ae (HEAD, p4/master, p4/HEAD, master) main
2585
+ | * 10d55fb (p4/project/dev) dev
2586
+ | * a43cfae Populate //depot/project/main/... //depot/project/dev/....
2587
+ |/
2588
+ * 2b83451 Project init</code></pre>
2589
+ </div>
2590
+ </div>
2591
+ <div class="paragraph">
2592
+ <p>Note the “@all” specifier in the depot path; that tells git-p4 to clone not just the latest changeset for that subtree, but all changesets that have ever touched those paths.
2593
+ This is closer to Git’s concept of a clone, but if you’re working on a project with a long history, it could take a while.</p>
2594
+ </div>
2595
+ <div class="paragraph">
2596
+ <p>The <code>--detect-branches</code> flag tells git-p4 to use Perforce’s branch specs to map the branches to Git refs.
2597
+ If these mappings aren’t present on the Perforce server (which is a perfectly valid way to use Perforce), you can tell git-p4 what the branch mappings are, and you get the same result:</p>
2598
+ </div>
2599
+ <div class="listingblock">
2600
+ <div class="content">
2601
+ <pre class="highlight"><code class="language-console" data-lang="console">$ git init project
2602
+ Initialized empty Git repository in /tmp/project/.git/
2603
+ $ cd project
2604
+ $ git config git-p4.branchList main:dev
2605
+ $ git clone --detect-branches //depot/project@all .</code></pre>
2606
+ </div>
2607
+ </div>
2608
+ <div class="paragraph">
2609
+ <p>Setting the <code>git-p4.branchList</code> configuration variable to <code>main:dev</code> tells git-p4 that “main” and “dev” are both branches, and the second one is a child of the first one.</p>
2610
+ </div>
2611
+ <div class="paragraph">
2612
+ <p>If we now <code>git checkout -b dev p4/project/dev</code> and make some commits, git-p4 is smart enough to target the right branch when we do <code>git p4 submit</code>.
2613
+ Unfortunately, git-p4 can’t mix shallow clones and multiple branches; if you have a huge project and want to work on more than one branch, you’ll have to <code>git p4 clone</code> once for each branch you want to submit to.</p>
2614
+ </div>
2615
+ <div class="paragraph">
2616
+ <p>For creating or integrating branches, you’ll have to use a Perforce client.
2617
+ Git-p4 can only sync and submit to existing branches, and it can only do it one linear changeset at a time.
2618
+ If you merge two branches in Git and try to submit the new changeset, all that will be recorded is a bunch of file changes; the metadata about which branches are involved in the integration will be lost.</p>
2619
+ </div>
2620
+ </div>
2621
+ </div>
2622
+ <div class="sect4">
2623
+ <h4 id="_git_and_perforce_summary">Git and Perforce Summary</h4>
2624
+ <div class="paragraph">
2625
+ <p>Git-p4 makes it possible to use a Git workflow with a Perforce server, and it’s pretty good at it.
2626
+ However, it’s important to remember that Perforce is in charge of the source, and you’re only using Git to work locally.
2627
+ Just be really careful about sharing Git commits; if you have a remote that other people use, don’t push any commits that haven’t already been submitted to the Perforce server.</p>
2628
+ </div>
2629
+ <div class="paragraph">
2630
+ <p>If you want to freely mix the use of Perforce and Git as clients for source control, and you can convince the server administrator to install it, Git Fusion makes using Git a first-class version-control client for a Perforce server.</p>
2631
+ </div>
2632
+ </div>
2633
+ </div>
2634
+ <div id="nav"><a href="Customizing-Git-Summary.html">prev</a> | <a href="ch00/_git_p4.html">next</a></div></div>
2635
+ </div>
2636
+
2637
+ </div>
2638
+ </div>
2639
+ <footer>
2640
+ <div class="site-source">
2641
+ <a href="https://git-scm.com/site">About this site</a><br>
2642
+ Patches, suggestions, and comments are welcome.
2643
+ </div>
2644
+ <div class="sfc-member">
2645
+ Git is a member of <a href="https://git-scm.com/sfc">Software Freedom Conservancy</a>
2646
+ </div>
2647
+ </footer>
2648
+ <a href="ch00/_git_svn.html#top" class="no-js scrollToTop" id="scrollToTop" data-label="Scroll to top">
2649
+ <img src="../../../images/icons/chevron-up@2x.png" width="20" height="20" alt="scroll-to-top"/>
2650
+ </a>
2651
+ <script src="../../../assets/application-38b0d42ff05ffea45841edebbd14b75b89585646153808e82907c2c5c11f324b.js"></script>
2652
+
2653
+ </div>
2654
+
2655
+ </body>
2656
+ </html>