eac_git 0.1.0 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/lib/eac_git/executables.rb +24 -4
  3. data/lib/eac_git/local.rb +5 -1
  4. data/lib/eac_git/local/dirty_files.rb +37 -0
  5. data/lib/eac_git/rspec.rb +17 -0
  6. data/lib/eac_git/version.rb +1 -1
  7. data/vendor/git-subrepo/Changes +110 -0
  8. data/vendor/git-subrepo/Intro.pod +509 -0
  9. data/vendor/git-subrepo/License +21 -0
  10. data/vendor/git-subrepo/Makefile +82 -0
  11. data/vendor/git-subrepo/Meta +28 -0
  12. data/vendor/git-subrepo/ReadMe.pod +698 -0
  13. data/vendor/git-subrepo/doc/comparison.swim +35 -0
  14. data/vendor/git-subrepo/doc/git-subrepo.swim +608 -0
  15. data/vendor/git-subrepo/doc/intro-to-subrepo.swim +387 -0
  16. data/vendor/git-subrepo/ext/bashplus/Changes +15 -0
  17. data/vendor/git-subrepo/ext/bashplus/License +21 -0
  18. data/vendor/git-subrepo/ext/bashplus/Makefile +45 -0
  19. data/vendor/git-subrepo/ext/bashplus/Meta +28 -0
  20. data/vendor/git-subrepo/ext/bashplus/ReadMe.pod +77 -0
  21. data/vendor/git-subrepo/ext/bashplus/bin/bash+ +43 -0
  22. data/vendor/git-subrepo/ext/bashplus/doc/bash+.swim +61 -0
  23. data/vendor/git-subrepo/ext/bashplus/lib/bash+.bash +92 -0
  24. data/vendor/git-subrepo/ext/bashplus/man/man1/bash+.1 +134 -0
  25. data/vendor/git-subrepo/ext/bashplus/man/man3/bash+.3 +134 -0
  26. data/vendor/git-subrepo/ext/bashplus/test/base.t +12 -0
  27. data/vendor/git-subrepo/ext/bashplus/test/fcopy.t +22 -0
  28. data/vendor/git-subrepo/ext/bashplus/test/lib/foo/bar.bash +3 -0
  29. data/vendor/git-subrepo/ext/bashplus/test/lib/foo/foo.bash +3 -0
  30. data/vendor/git-subrepo/ext/bashplus/test/source-bash+-std.t +18 -0
  31. data/vendor/git-subrepo/ext/bashplus/test/source-bash+.t +23 -0
  32. data/vendor/git-subrepo/ext/bashplus/test/test.bash +70 -0
  33. data/vendor/git-subrepo/ext/bashplus/test/use.t +19 -0
  34. data/vendor/git-subrepo/ext/test-more-bash/Changes +15 -0
  35. data/vendor/git-subrepo/ext/test-more-bash/License +21 -0
  36. data/vendor/git-subrepo/ext/test-more-bash/Makefile +20 -0
  37. data/vendor/git-subrepo/ext/test-more-bash/Meta +30 -0
  38. data/vendor/git-subrepo/ext/test-more-bash/ReadMe.pod +115 -0
  39. data/vendor/git-subrepo/ext/test-more-bash/doc/test-more.swim +89 -0
  40. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/Changes +15 -0
  41. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/License +21 -0
  42. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/Makefile +45 -0
  43. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/Meta +28 -0
  44. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/ReadMe.pod +77 -0
  45. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+ +43 -0
  46. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/doc/bash+.swim +61 -0
  47. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/lib/bash+.bash +92 -0
  48. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/man/man1/bash+.1 +134 -0
  49. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/man/man3/bash+.3 +134 -0
  50. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/base.t +12 -0
  51. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/fcopy.t +22 -0
  52. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/lib/foo/bar.bash +3 -0
  53. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/lib/foo/foo.bash +3 -0
  54. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/source-bash+-std.t +18 -0
  55. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/source-bash+.t +23 -0
  56. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/test.bash +70 -0
  57. data/vendor/git-subrepo/ext/test-more-bash/ext/bashplus/test/use.t +19 -0
  58. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/Changes +15 -0
  59. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/License +21 -0
  60. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/Makefile +37 -0
  61. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/Meta +28 -0
  62. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/ReadMe.pod +66 -0
  63. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/doc/test-tap.swim +48 -0
  64. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/lib/test/tap.bash +153 -0
  65. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/man/man3/test-tap.3 +119 -0
  66. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/bail_out.t +13 -0
  67. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/done.t +10 -0
  68. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/fail.t +20 -0
  69. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/fail_fast.t +15 -0
  70. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/helper.bash +9 -0
  71. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/pass.t +9 -0
  72. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/plan.t +10 -0
  73. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/skip_all.t +20 -0
  74. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/tap.t +13 -0
  75. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/test/bail.t +14 -0
  76. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/test/fail.t +7 -0
  77. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/test/fail_fast.t +12 -0
  78. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/test/skip-all-init.t +8 -0
  79. data/vendor/git-subrepo/ext/test-more-bash/ext/test-tap-bash/test/test/skip-all-plan.t +9 -0
  80. data/vendor/git-subrepo/ext/test-more-bash/lib/test/more.bash +95 -0
  81. data/vendor/git-subrepo/ext/test-more-bash/man/man3/test-more.3 +173 -0
  82. data/vendor/git-subrepo/ext/test-more-bash/test/fail.t +20 -0
  83. data/vendor/git-subrepo/ext/test-more-bash/test/more.t +20 -0
  84. data/vendor/git-subrepo/ext/test-more-bash/test/pass.t +9 -0
  85. data/vendor/git-subrepo/ext/test-more-bash/test/setup +8 -0
  86. data/vendor/git-subrepo/ext/test-more-bash/test/skip_all.t +11 -0
  87. data/vendor/git-subrepo/ext/test-more-bash/test/test/fail1.t +12 -0
  88. data/vendor/git-subrepo/ext/test-more-bash/test/test/skip_all.t +10 -0
  89. data/vendor/git-subrepo/lib/git-subrepo +1903 -0
  90. data/vendor/git-subrepo/lib/git-subrepo.d/bash+.bash +1 -0
  91. data/vendor/git-subrepo/lib/git-subrepo.d/help-functions.bash +339 -0
  92. data/vendor/git-subrepo/man/man1/git-subrepo.1 +743 -0
  93. data/vendor/git-subrepo/note/0.4.0 +12 -0
  94. data/vendor/git-subrepo/note/AllGitCmds +148 -0
  95. data/vendor/git-subrepo/note/Cases +32 -0
  96. data/vendor/git-subrepo/note/Commands +33 -0
  97. data/vendor/git-subrepo/note/Dags +199 -0
  98. data/vendor/git-subrepo/note/Gists +7 -0
  99. data/vendor/git-subrepo/note/Links +25 -0
  100. data/vendor/git-subrepo/note/Plugins +10 -0
  101. data/vendor/git-subrepo/note/Spec +39 -0
  102. data/vendor/git-subrepo/note/Story1 +57 -0
  103. data/vendor/git-subrepo/note/ToDo +55 -0
  104. data/vendor/git-subrepo/note/design.swim +137 -0
  105. data/vendor/git-subrepo/note/design2.swim +85 -0
  106. data/vendor/git-subrepo/note/init-test +38 -0
  107. data/vendor/git-subrepo/note/pull-dance.txt +18 -0
  108. data/vendor/git-subrepo/note/recreate-rebase-conflict.sh +56 -0
  109. data/vendor/git-subrepo/note/subtree-rebase-fail-example/test.bash +29 -0
  110. data/vendor/git-subrepo/note/test-subrepo-push.sh +69 -0
  111. data/vendor/git-subrepo/note/test.sh +58 -0
  112. data/vendor/git-subrepo/pkg/bin/generate-completion.pl +210 -0
  113. data/vendor/git-subrepo/pkg/bin/generate-help-functions.pl +89 -0
  114. data/vendor/git-subrepo/share/completion.bash +42 -0
  115. data/vendor/git-subrepo/share/enable-completion.sh +50 -0
  116. data/vendor/git-subrepo/share/git-completion.bash +2738 -0
  117. data/vendor/git-subrepo/share/zsh-completion/_git-subrepo +81 -0
  118. data/vendor/git-subrepo/test/branch-all.t +41 -0
  119. data/vendor/git-subrepo/test/branch-rev-list-one-path.t +43 -0
  120. data/vendor/git-subrepo/test/branch-rev-list.t +47 -0
  121. data/vendor/git-subrepo/test/branch.t +52 -0
  122. data/vendor/git-subrepo/test/clean.t +43 -0
  123. data/vendor/git-subrepo/test/clone-annotated-tag.t +45 -0
  124. data/vendor/git-subrepo/test/clone.t +107 -0
  125. data/vendor/git-subrepo/test/compile.t +19 -0
  126. data/vendor/git-subrepo/test/config.t +58 -0
  127. data/vendor/git-subrepo/test/encode.t +91 -0
  128. data/vendor/git-subrepo/test/error.t +171 -0
  129. data/vendor/git-subrepo/test/fetch.t +43 -0
  130. data/vendor/git-subrepo/test/gitignore.t +61 -0
  131. data/vendor/git-subrepo/test/init.t +64 -0
  132. data/vendor/git-subrepo/test/issue29.t +98 -0
  133. data/vendor/git-subrepo/test/issue95.t +98 -0
  134. data/vendor/git-subrepo/test/issue96.t +96 -0
  135. data/vendor/git-subrepo/test/pull-all.t +38 -0
  136. data/vendor/git-subrepo/test/pull-merge.t +113 -0
  137. data/vendor/git-subrepo/test/pull-message.t +88 -0
  138. data/vendor/git-subrepo/test/pull-new-branch.t +58 -0
  139. data/vendor/git-subrepo/test/pull-ours.t +90 -0
  140. data/vendor/git-subrepo/test/pull-theirs.t +82 -0
  141. data/vendor/git-subrepo/test/pull-twice.t +44 -0
  142. data/vendor/git-subrepo/test/pull-worktree.t +40 -0
  143. data/vendor/git-subrepo/test/pull.t +99 -0
  144. data/vendor/git-subrepo/test/push-after-init.t +51 -0
  145. data/vendor/git-subrepo/test/push-force.t +56 -0
  146. data/vendor/git-subrepo/test/push-new-branch.t +61 -0
  147. data/vendor/git-subrepo/test/push-no-changes.t +29 -0
  148. data/vendor/git-subrepo/test/push-squash.t +56 -0
  149. data/vendor/git-subrepo/test/push.t +176 -0
  150. data/vendor/git-subrepo/test/reclone.t +45 -0
  151. data/vendor/git-subrepo/test/repo/bar/HEAD +1 -0
  152. data/vendor/git-subrepo/test/repo/bar/config +4 -0
  153. data/vendor/git-subrepo/test/repo/bar/objects/1f/0c4b264caed0126814a0ede851a1e0b4e16ae6 +0 -0
  154. data/vendor/git-subrepo/test/repo/bar/objects/87/46903fdb1b9c2101377880125917c2e05b4d69 +0 -0
  155. data/vendor/git-subrepo/test/repo/bar/objects/94/c86ffc745232d89f78c6f895e11e71272518db +0 -0
  156. data/vendor/git-subrepo/test/repo/bar/objects/c6/76c57b6576743fa56278527aa60ebd2e202a7c +0 -0
  157. data/vendor/git-subrepo/test/repo/bar/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  158. data/vendor/git-subrepo/test/repo/bar/objects/f6/2a8ff3feadf39b0a98f1a86ec6d1eb33858ee9 +0 -0
  159. data/vendor/git-subrepo/test/repo/bar/refs/heads/master +1 -0
  160. data/vendor/git-subrepo/test/repo/bar/refs/tags/A +1 -0
  161. data/vendor/git-subrepo/test/repo/foo/HEAD +1 -0
  162. data/vendor/git-subrepo/test/repo/foo/config +4 -0
  163. data/vendor/git-subrepo/test/repo/foo/objects/a0/f4cdaaf533a936296cdebbed8206c3b9ededa8 +0 -0
  164. data/vendor/git-subrepo/test/repo/foo/objects/e2/1291a1ad392a9d4c51dd9586804f1467b28afd +0 -0
  165. data/vendor/git-subrepo/test/repo/foo/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  166. data/vendor/git-subrepo/test/repo/foo/refs/heads/master +1 -0
  167. data/vendor/git-subrepo/test/repo/init/HEAD +1 -0
  168. data/vendor/git-subrepo/test/repo/init/config +5 -0
  169. data/vendor/git-subrepo/test/repo/init/objects/11/523f5dcf03b4c89b592dc8a3d0308f68da2386 +0 -0
  170. data/vendor/git-subrepo/test/repo/init/objects/14/2addf8ec5f37334e837440122c62f2c68a29ad +0 -0
  171. data/vendor/git-subrepo/test/repo/init/objects/32/5180321750a21cd7a4e7ecda319e557a4f6a09 +2 -0
  172. data/vendor/git-subrepo/test/repo/init/objects/3d/918c6901c02f43af5d31779dd5e1f9166aeb36 +0 -0
  173. data/vendor/git-subrepo/test/repo/init/objects/3e/4cb596066dce63ba4d047abddb677389b65e19 +0 -0
  174. data/vendor/git-subrepo/test/repo/init/objects/4b/6e53022e7a04f07887697e4f3d7c377fd9822b +0 -0
  175. data/vendor/git-subrepo/test/repo/init/objects/58/931fc1bd559b59c41ea738fc7ad04f9ad01bd3 +0 -0
  176. data/vendor/git-subrepo/test/repo/init/objects/5e/c0c28e1b806f25efdca18fcf7a74b49c3755bd +0 -0
  177. data/vendor/git-subrepo/test/repo/init/objects/75/fa6584e748f57eff06eebdc55e9ac21d4fcbf2 +1 -0
  178. data/vendor/git-subrepo/test/repo/init/objects/80/2d5edbd5e1cb7fca82b5bd38e7c8a0a496fb20 +0 -0
  179. data/vendor/git-subrepo/test/repo/init/objects/94/7b3d714c38791e95ad6f928b48c98bb8708acd +0 -0
  180. data/vendor/git-subrepo/test/repo/init/objects/95/e1f2df3f4d5f3d7a60588c25a7ca8a913d3c2a +1 -0
  181. data/vendor/git-subrepo/test/repo/init/objects/b1/5f4a7666baf40d949548ead946a3370e273479 +0 -0
  182. data/vendor/git-subrepo/test/repo/init/objects/c3/ee8978c4c5d84c3b7d00ba8e5906933d027882 +0 -0
  183. data/vendor/git-subrepo/test/repo/init/objects/c8/b0bffbc405ef3fad7354ff833fbec36d67ddfa +3 -0
  184. data/vendor/git-subrepo/test/repo/init/objects/dd/8bdb934ec848137f011fe423b185505c343626 +2 -0
  185. data/vendor/git-subrepo/test/repo/init/objects/e2/9be58c767cfeb27235c995d293a7d71aac0135 +2 -0
  186. data/vendor/git-subrepo/test/repo/init/objects/ee/1224401fc6aac595145fa727dcf6706ac8aec1 +1 -0
  187. data/vendor/git-subrepo/test/repo/init/objects/f1/cc1a657b2e805c400f5dcaaa76bd29c6178b1b +0 -0
  188. data/vendor/git-subrepo/test/repo/init/refs/heads/master +1 -0
  189. data/vendor/git-subrepo/test/setup +205 -0
  190. data/vendor/git-subrepo/test/status.t +68 -0
  191. data/vendor/git-subrepo/test/submodule.t +45 -0
  192. metadata +190 -4
@@ -0,0 +1,387 @@
1
+ = Introducing Git Subrepos
2
+
3
+ There is a new git command called `subrepo` that is meant to be a solid
4
+ alternative to the `submodule` and `subtree` commands. All 3 of these commands
5
+ allow you to include external repositories (pinned to specific commits) in
6
+ your main repository. This is an often needed feature for project development
7
+ under a source control system like Git. Unfortunately, the `submodule` command
8
+ is severely lacking, and the `subtree` command (an attempt to make things
9
+ better) is also very flawed. Fortunately, the `subrepo` command is here to
10
+ save the day.
11
+
12
+ This article will discuss how the previous commands work, and where they go
13
+ wrong, while explaining how the new `subrepo` command fixes the issues.
14
+
15
+ It should be noted that there are 3 distinct roles (ways people use repos)
16
+ involved in discussing this topic:
17
+
18
+ * *owner* — The primary author and repo owner
19
+ * *collaborators* — Other developers who contribute to the repo
20
+ * *users* — People who simply use the repo software
21
+
22
+ == Introducing `subrepo`
23
+
24
+ While the main point is to show how subrepo addresses the shortcomings of
25
+ submodule and subtree, I'll start by giving a quick intro to the subrepo
26
+ command.
27
+
28
+ Let's say that you have a project repo called 'freebird' and you want to have
29
+ it include 2 other external repos, 'lynyrd' and 'skynyrd'. You would do the
30
+ following:
31
+
32
+ git clone git@github.com/you/freebird
33
+ cd freebird
34
+ git subrepo clone git@github.com/you/lynyrd ext/lynyrd
35
+ git subrepo clone git@github.com/you/skynyrd ext/skynyrd --branch=1975
36
+
37
+ What these commands do (at a high level) should be obvious. They "clone"
38
+ (add) the repos content into the subdirectories you told them to. The details
39
+ of what is happening to your repo will be discussed later, but adding new
40
+ subrepos is easy. If you need to update the subrepos later:
41
+
42
+ git subrepo pull ext/lynyrd
43
+ git subrepo pull ext/skynyrd --branch=1976
44
+
45
+ The lynyrd repo is tracking the upstream master branch, and you've changed the
46
+ skynyrd subrepo to the 1976 branch. Since these subrepos are owned by 'you',
47
+ you might want to change them in the context of your freebird repo. When
48
+ things are working, you can push the subrepo changes back:
49
+
50
+ git subrepo push ext/lynyrd
51
+ git subrepo push ext/skynyrd
52
+
53
+ Looks simple right? It's supposed to be. The intent of `subrepo` is to do the
54
+ right things, and to not cause problems.
55
+
56
+ Of course there's more to it under the hood, and that's what the rest of this
57
+ article is about.
58
+
59
+ == Git Submodules
60
+
61
+ Submodules tend to receive a lot of bad press. Here's some of it:
62
+
63
+ * http://ayende.com/blog/4746/the-problem-with-git-submodules
64
+ * http://somethingsinistral.net/blog/git-submodules-are-probably-not-the-answer/
65
+ * http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/
66
+
67
+ A quick recap of some of the good and bad things about submodules:
68
+
69
+ Good:
70
+
71
+ * Use an external repo in a dedicated subdir of your project.
72
+ * Pin the external repo to a specific commit.
73
+ * The `git-submodule` command is a core part of the Git project.
74
+
75
+ Bad:
76
+
77
+ * Users have to know a repo has submodules.
78
+ * Users have to get the subrepos manually.
79
+ * Pulling a repo with submodules won't pull in the new submodule changes.
80
+ * A submodule will break if the referenced repo goes away.
81
+ * A submodule will break if a forced push removes the referenced commit.
82
+ * Can't use different submodules/commits per main project branch.
83
+ * Can't "try out" a submodule on alternate branch.
84
+ * Main repo can be pushed upstream pointing to unpushed submod commits.
85
+ * Command capability differs across Git versions.
86
+ * Often need to change remote url, to push submodule changes upstream.
87
+ * Removing or renaming a submodule requires many steps.
88
+
89
+ Internally, submodules are a real mess. They give the strong impression of
90
+ being bolted on, well after Git was designed. Some commands are aware of the
91
+ existence of submodules (although usually half-heartedly), and many commands
92
+ are oblivious. For instance the git-clone command has a `--recursive` option
93
+ to clone all subrepos, but it's not a default, so you still need to be aware
94
+ of the need. The git-checkout command does nothing with the submodules, even
95
+ if they are intended to differ across branches.
96
+
97
+ Let's talk a bit about how submodules are implemented in Git. Information
98
+ about them is stored in 3 different places (in the top level repo directory):
99
+
100
+ * `.gitmodules`
101
+ * `.git/config`
102
+ * `.git/modules` — The submodule repo's meta data (refs/objects)
103
+
104
+ So some of the information lives in the repo history (.gitmodules), but other
105
+ info (.git/) is only known to the local repo.
106
+
107
+ In addition, the submodule introduces a new low level concept, to the
108
+ commit/tree/blob graph. Normally a git tree object points to blob (file)
109
+ objects and more tree (directory) objects. Submodules have tree objects point
110
+ to *commit* objects. While this seems clever and somewhat reasonable, it also
111
+ means that every other git command (which was built on the super clean Git
112
+ data model) has to be aware of this new possibility (and deal with it
113
+ appropriately).
114
+
115
+ The point is that, while submodules are a real need, and a lot of work has
116
+ gone into making them work decently, they are essentially a kludge to the Git
117
+ model, and it is quite understandable why they haven't worked out as well as
118
+ people would expect.
119
+
120
+ NOTE: Submodules /are/ getting better with each release of Git, but it's still
121
+ an endless catch up game.
122
+
123
+ == Git Subtrees
124
+
125
+ One day, someone decided to think different. Instead of pointing to external
126
+ repos, why not just include them into the main repo (but also allow them to be
127
+ pulled and pushed separately as needed)?
128
+
129
+ At first this may feel like a wasteful approach. Why keep other repos
130
+ physically inside your main one? But if you think about it abstractly, what's
131
+ the difference? You want your users and collaborators to have all this code
132
+ because your project needs it. So why worry about how it happens? In the end,
133
+ the choice is yours, but I've grown very comfortable with this concept and
134
+ I'll try to justify it well. I should note that the first paragraph of the
135
+ `submodule` doc suggests considering this alternative.
136
+
137
+ The big win here is that you can do this using the existing git model.
138
+ Nothing new is added. You are just adding commits to a history. You can do it
139
+ different on every branch. You can merge branches sensibly.
140
+
141
+ The git-subtree command seems to have been inspired by Git's subtree merge
142
+ strategy, which it uses internally, and possibly got its name from. A subtree
143
+ merge allows you to take a completely separate Git history and make it be a
144
+ subdirectory of your repo.
145
+
146
+ Adding a subtree was the easy part. All that needed to be done after that was
147
+ to figure out a way to pull upstream changes and push local ones back
148
+ upstream. And that's what the `git-subtree` command does.
149
+
150
+ So what's the problem with git-subtree then?
151
+
152
+ Well unfortunately, it drops a few balls. The main problems come down to an
153
+ overly complicated commandline UX, poor collaborator awareness, and a fragile
154
+ and messy implementation.
155
+
156
+ Good:
157
+
158
+ * Use an external repo in a dedicated subdir of your project.
159
+ * Pin the external repo to a specific commit.
160
+ * Users get everything with a normal clone command.
161
+ * Users don't need to know that subtrees are involved.
162
+ * Can use different submodules/commits per main project branch.
163
+ * Users don't need the subtree command. Only owners and collaborators.
164
+
165
+ Bad:
166
+ * The remote url and branch info is not saved (except in the history).
167
+ * Owners and collaborators have to enter the remote for every command.
168
+ * Collaborators aren't made aware that subtrees are involved.
169
+ * Pulled history is not squashed by default.
170
+ * Creates a messy historical view. (See below)
171
+ * Bash code is complicated.
172
+ * Only one test file. Currently is failing.
173
+
174
+ As you can see, subtree makes quite a few things better, but after trying it
175
+ for a while, the experience was more annoying than submodules. For example,
176
+ consider this usage:
177
+
178
+ $ git subtree add --squash --prefix=foo git@github.com:my/thing mybranch
179
+ # weeks go by…
180
+ $ git subtree pull --squash --prefix=foo git@github.com:my/thing mybranch
181
+ # time to push local subtree changes back upstream
182
+ $ git subtree push --prefix=foo git@github.com:my/thing mybranch
183
+
184
+ The first thing you notice is the overly verbose syntax. It's justified in the
185
+ first command, but in the other 2 commands I really don't want to have to
186
+ remember what the remote and branch are that I'm using.
187
+
188
+ Moreover, my collaborators have no idea that subtrees are involved, let alone
189
+ where they came from.
190
+
191
+ Consider the equivalent subrepo commands:
192
+
193
+ $ git subrepo clone git@github.com:my/thing foo -b mybranch
194
+ $ git subrepo pull foo
195
+ $ git subrepo push foo
196
+
197
+ Collaborators see a file called 'foo/.gitrepo', and know that the subdir is a
198
+ subrepo. The file contains all the information needed by future commands
199
+ applied to that subrepo.
200
+
201
+ == Git Subrepos
202
+
203
+ Now is a good time to dive into the techinical aspects of the `subrepo`
204
+ command, but first let me explain how it came about.
205
+
206
+ As you may have surmised by now, I am the author of git-subrepo. I'd used
207
+ submodules on and off for years, and when I became aware of subtree I gave it
208
+ a try, but I quickly realized its problems. I decided maybe it could be
209
+ improved. I decided to write down my expected commandline usage and my ideals
210
+ of what it would and would not do. Then I set off to implement it. It's been a
211
+ long road, but what I ended up with was even better than what I wanted from
212
+ the start.
213
+
214
+ Let's review the Goods and Bads:
215
+
216
+ Good:
217
+
218
+ * Use an external repo in a dedicated subdir of your project.
219
+ * Pin the external repo to a specific commit.
220
+ * Users get everything with a normal clone command.
221
+ * Users don't need to know that subrepos are involved.
222
+ * Can use different submodules/commits per main project branch.
223
+ * Meta info is kept in an obvious place.
224
+ * Everyone knows when a subdir is a subrepo.
225
+ * Commandline UX is minimal and intuitive.
226
+ * Pulled history is always squashed out locally.
227
+ * Pushed history is kept intact.
228
+ * Creates a clean historical view. (See below)
229
+ * Bash code is very simple and easy to follow.
230
+ * Comprehensive test suite. Currently passing on travis:
231
+
232
+ <badge travis ingydotnet/git-subrepo>
233
+
234
+ Bad:
235
+
236
+ * --Subrepo is very new.-- (no longer true)
237
+ * --Not well tested in the wild.-- (no longer true)
238
+
239
+ This review may seem somewhat slanted, but I honestly am not aware of any
240
+ "bad" points that I'm not disclosing. That said, I am sure time will reveal
241
+ bugs and shortcomings. Those can usually be fixed. Hopefully the *model* is
242
+ correct, because that's harder to fix down the road.
243
+
244
+ OK. So how does it all work?
245
+
246
+ There are 3 main commands: clone/pull/push. Let's start with the clone
247
+ command. This is the easiest part. You give it a remote url, possibly a new
248
+ subdir to put it, and possibly a remote branch to use. I say possibly, because
249
+ the command can guess the subdir name (just like the git-clone command does),
250
+ and the branch can be the upstream default branch.
251
+
252
+ Given this we do the following steps internally:
253
+
254
+ * Fetch the remote content (for a specific refspec)
255
+ * Read the remote head tree into the index
256
+ * Checkout the index into the new subdir
257
+ * Create a new subrepo commit object for the subdir content
258
+ * Add a state file called .gitrepo to the new subrepo/subdir
259
+ * Amend the merge commit with this new file
260
+
261
+ This process adds something like this to the top of your history:
262
+
263
+ * 9b6ddc9 git subrepo clone git@github.com:you/foo.git foo/
264
+ * 37c61a5 Previous head commit of your repo
265
+
266
+ The entire history has been squashed down into one commit, and placed on top of
267
+ your history. This is important as it keeps your history as clean as possible.
268
+ You don't need to have the subrepo history in your main project, since it is
269
+ immutably available elsewhere, and you have a pointer to that place.
270
+
271
+ The new foo/.gitrepo file looks like this:
272
+
273
+ [subrepo]
274
+ remote = git@github.com:you/foo.git
275
+ branch = master
276
+ commit = 14c96c6931b41257b2d42b2edc67ddc659325823
277
+ parent = 37c61a5a234f5dd6f5c2aec037509f50d3a79b8f
278
+ cmdver = 0.1.0
279
+
280
+ It contains all the info needed now and later. Note that the repo url is the
281
+ generally pushable form, rather than the publically readable (https://…) form.
282
+ This is the best practice. Users of your repo don't need access to this url,
283
+ because the content is already in your repo. Only you and your collaborators
284
+ need this url to pull/push in the future.
285
+
286
+ The next command is the pull command. Normally you just give it the subrepo's
287
+ subdir path (although you can change the branch with -b), and it will get the
288
+ other info from the subdir/.gitrepo file.
289
+
290
+ The pull command does these steps:
291
+
292
+ * Fetch the upstream content
293
+ * Check if anything needs pulling
294
+ * Create a branch of local subrepo commits since last pull
295
+ * Rebase this branch onto the upstream commits
296
+ * Commit the HEAD of the rebased content
297
+ * Update/amend the .gitrepo file
298
+
299
+ === Clean History
300
+
301
+ I've talked a bit about clean history but let me show you a comparison between
302
+ subrepo and subtree. Let's run this command sequence using both methods. Note
303
+ the differences between /both/ the command syntax required, and the branch
304
+ history produced.
305
+
306
+ Subrepo first:
307
+
308
+ $ git subrepo clone git@github.com:user/abc
309
+ $ git subrepo clone git@github.com:user/def xyz
310
+ $ git subrepo pull abc
311
+ $ git subrepo pull xyz
312
+
313
+ The resulting history is:
314
+
315
+ * b1f60cc subrepo pull xyz
316
+ * 4fb0276 subrepo pull abc
317
+ * bcef2a0 subrepo clone git@github.com:user/def xyz
318
+ * bebf0db subrepo clone git@github.com:user/abc
319
+ * 64eeaa6 (origin/master, origin/HEAD) O HAI FREND
320
+
321
+ Compare that to *subtree*. This:
322
+
323
+ $ git subtree add abc git@github.com:user/abc master
324
+ $ git subtree add xyz git@github.com:user/def master
325
+ $ git subtree pull abc git@github.com:user/abc master
326
+ $ git subtree pull xyz git@github.com:user/def master
327
+
328
+ Produces this:
329
+
330
+ * 739e45a (HEAD, master) Merge commit '5f563469d886d53e19cb908b3a64e4229f88a2d1'
331
+ |\
332
+ | * 5f56346 Squashed 'xyz/' changes from 08c7421..365409f
333
+ * | 641f5e5 Merge commit '8d88e90ce5f653ed2e7608a71b8693a2174ea62a'
334
+ |\ \
335
+ | * | 8d88e90 Squashed 'abc/' changes from 08c7421..365409f
336
+ * | | 1703ed2 Merge commit '0e091b672c4bbbbf6bc4f6694c475d127ffa21eb' as 'xyz'
337
+ |\ \ \
338
+ | | |/
339
+ | |/|
340
+ | * | 0e091b6 Squashed 'xyz/' content from commit 08c7421
341
+ | /
342
+ * | 07b77e7 Merge commit 'cd2b30a0229d931979ed4436b995875ec563faea' as 'abc'
343
+ |\ \
344
+ | |/
345
+ | * cd2b30a Squashed 'abc/' content from commit 08c7421
346
+ * 64eeaa6 (origin/master, origin/HEAD) O HAI FREND
347
+
348
+ This was from a minimal case. Subtree history (when viewed this way at least)
349
+ gets unreasonably ugly fast. Subrepo history, by contrast, always looks as
350
+ clean as shown.
351
+
352
+ The final command, push, bascially just does the pull/rebase dance above
353
+ described, and pushes the resulting history back. It does not squash the
354
+ commits made locally, because it assumed that when you changed the local
355
+ subrepo, you made messages that were intended to eventually be published back
356
+ upstream.
357
+
358
+ == Conflict Resolution
359
+
360
+ The commands described above can also be done "by hand". If something fails
361
+ during a pull or push (generally in the rebasing) then the command will tell
362
+ you what to do to finish up.
363
+
364
+ You might choose to do everything by hand, and do your own merging strategies.
365
+ This is perfectly reasonable. The `subrepo` command offers a few other helper
366
+ commands to help you get the job done:
367
+
368
+ * `fetch` - Fetch the upstream and create a `subrepo/remote/<subdir>` ref.
369
+ * `branch` - Create a branch of local subdir commits since the last pull,
370
+ called `subrepo/<subdir>`.
371
+ * `commit` - Commit a merged branch's HEAD back into your repo.
372
+ * `status` - Show lots of useful info about the current state of the subrepos.
373
+ * `clean` - Remove branches, ref and remotes created by subrepo commands.
374
+ * `help` - Read the complete documentation!
375
+
376
+ == Conclusion
377
+
378
+ Hopefully by now, you see that submodules are a painful choice with a dubious
379
+ future, and that subtree, while a solid idea has many usage issues.
380
+
381
+ Give `subrepo` a try. It's painless, easily revertable and just might be what
382
+ the doctor ordered.
383
+
384
+ == Reference Links
385
+
386
+ * http://longair.net/blog/2010/06/02/git-submodules-explained/
387
+ * http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/
@@ -0,0 +1,15 @@
1
+ ---
2
+ version: 0.0.7
3
+ date: Sat Jan 23 16:28:59 PST 2016
4
+ changes:
5
+ - Update tooling, and copyright
6
+ ---
7
+ version: 0.0.6
8
+ date: Fri Jan 23 21:05:15 PST 2015
9
+ changes:
10
+ - Update tooling, and copyright
11
+ ---
12
+ version: 0.0.1
13
+ date: Sun Oct 27 19:07:51 PDT 2013
14
+ changes:
15
+ - First release.
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright © 2013-2016 Ingy döt Net
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the ‘Software’), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,45 @@
1
+ ifeq ($(MAKECMDGOALS),install)
2
+ ifeq "$(shell bpan version 2>/dev/null)" ""
3
+ $(error 'BPAN not installed. See http://bpan.org')
4
+ endif
5
+ endif
6
+
7
+ NAME := bash+
8
+ LIB := lib/$(NAME).bash
9
+ DOC := doc/$(NAME).swim
10
+ MAN1 := man/man1
11
+ MAN3 := man/man3
12
+
13
+ INSTALL_LIB ?= $(shell bpan env BPAN_LIB)
14
+ INSTALL_DIR ?= test
15
+ INSTALL_MAN1 ?= $(shell bpan env BPAN_MAN1)
16
+ INSTALL_MAN3 ?= $(shell bpan env BPAN_MAN3)
17
+
18
+ default: help
19
+
20
+ help:
21
+ @echo 'Rules: test, install, doc'
22
+
23
+ .PHONY: test
24
+ test:
25
+ prove $(PROVEOPT:%=% )test/
26
+
27
+ install:
28
+ install -C -d -m 0755 $(INSTALL_LIB)/$(INSTALL_DIR)/
29
+ install -C -m 0755 $(LIB) $(INSTALL_LIB)/$(INSTALL_DIR)/
30
+ install -C -d -m 0755 $(INSTALL_MAN1)/
31
+ install -C -d -m 0755 $(INSTALL_MAN3)/
32
+ install -C -m 0644 $(MAN1)/$(NAME).1 $(INSTALL_MAN1)/
33
+ install -C -m 0644 $(MAN3)/$(NAME).3 $(INSTALL_MAN3)/
34
+
35
+ .PHONY: doc
36
+ doc: ReadMe.pod $(MAN1)/$(NAME).1 $(MAN3)/$(NAME).3
37
+
38
+ ReadMe.pod: $(DOC)
39
+ swim --to=pod --complete --wrap $< > $@
40
+
41
+ $(MAN1)/%.1: doc/%.swim
42
+ swim --to=man $< > $@
43
+
44
+ $(MAN3)/%.3: doc/%.swim
45
+ swim --to=man $< > $@