|
| 1 | +##Submodules |
| 2 | + |
| 3 | +Large projects are often composed of smaller, self-contained modules. For |
| 4 | +example, an embedded Linux distribution's source tree would include every |
| 5 | +piece of software in the distribution with some local modifications; a movie |
| 6 | +player might need to build against a specific, known-working version of a |
| 7 | +decompression library; several independent programs might all share the same |
| 8 | +build scripts. |
| 9 | + |
| 10 | +With centralized revision control systems this is often accomplished by |
| 11 | +including every module in one single repository. Developers can check out |
| 12 | +all modules or only the modules they need to work with. They can even modify |
| 13 | +files across several modules in a single commit while moving things around |
| 14 | +or updating APIs and translations. |
| 15 | + |
| 16 | +Git does not allow partial checkouts, so duplicating this approach in Git |
| 17 | +would force developers to keep a local copy of modules they are not |
| 18 | +interested in touching. Commits in an enormous checkout would be slower |
| 19 | +than you'd expect as Git would have to scan every directory for changes. |
| 20 | +If modules have a lot of local history, clones would take forever. |
| 21 | + |
| 22 | +On the plus side, distributed revision control systems can much better |
| 23 | +integrate with external sources. In a centralized model, a single arbitrary |
| 24 | +snapshot of the external project is exported from its own revision control |
| 25 | +and then imported into the local revision control on a vendor branch. All |
| 26 | +the history is hidden. With distributed revision control you can clone the |
| 27 | +entire external history and much more easily follow development and re-merge |
| 28 | +local changes. |
| 29 | + |
| 30 | +Git's submodule support allows a repository to contain, as a subdirectory, a |
| 31 | +checkout of an external project. Submodules maintain their own identity; |
| 32 | +the submodule support just stores the submodule repository location and |
| 33 | +commit ID, so other developers who clone the containing project |
| 34 | +("superproject") can easily clone all the submodules at the same revision. |
| 35 | +Partial checkouts of the superproject are possible: you can tell Git to |
| 36 | +clone none, some or all of the submodules. |
| 37 | + |
| 38 | +The linkgit:git-submodule[1] command is available since Git 1.5.3. Users |
| 39 | +with Git 1.5.2 can look up the submodule commits in the repository and |
| 40 | +manually check them out; earlier versions won't recognize the submodules at |
| 41 | +all. |
| 42 | + |
| 43 | +To see how submodule support works, create (for example) four example |
| 44 | +repositories that can be used later as a submodule: |
| 45 | + |
| 46 | + $ mkdir ~/git |
| 47 | + $ cd ~/git |
| 48 | + $ for i in a b c d |
| 49 | + do |
| 50 | + mkdir $i |
| 51 | + cd $i |
| 52 | + git init |
| 53 | + echo "module $i" > $i.txt |
| 54 | + git add $i.txt |
| 55 | + git commit -m "Initial commit, submodule $i" |
| 56 | + cd .. |
| 57 | + done |
| 58 | + |
| 59 | +Now create the superproject and add all the submodules: |
| 60 | + |
| 61 | + $ mkdir super |
| 62 | + $ cd super |
| 63 | + $ git init |
| 64 | + $ for i in a b c d |
| 65 | + do |
| 66 | + git submodule add ~/git/$i |
| 67 | + done |
| 68 | + |
| 69 | +NOTE: Do not use local URLs here if you plan to publish your superproject! |
| 70 | + |
| 71 | +See what files `git-submodule` created: |
| 72 | + |
| 73 | + $ ls -a |
| 74 | + . .. .git .gitmodules a b c d |
| 75 | + |
| 76 | +The `git-submodule add` command does a couple of things: |
| 77 | + |
| 78 | +- It clones the submodule under the current directory and by default checks out |
| 79 | + the master branch. |
| 80 | +- It adds the submodule's clone path to the linkgit:gitmodules[5] file and |
| 81 | + adds this file to the index, ready to be committed. |
| 82 | +- It adds the submodule's current commit ID to the index, ready to be |
| 83 | + committed. |
| 84 | + |
| 85 | +Commit the superproject: |
| 86 | + |
| 87 | + |
| 88 | + $ git commit -m "Add submodules a, b, c and d." |
| 89 | + |
| 90 | +Now clone the superproject: |
| 91 | + |
| 92 | + $ cd .. |
| 93 | + $ git clone super cloned |
| 94 | + $ cd cloned |
| 95 | + |
| 96 | +The submodule directories are there, but they're empty: |
| 97 | + |
| 98 | + $ ls -a a |
| 99 | + . .. |
| 100 | + $ git submodule status |
| 101 | + -d266b9873ad50488163457f025db7cdd9683d88b a |
| 102 | + -e81d457da15309b4fef4249aba9b50187999670d b |
| 103 | + -c1536a972b9affea0f16e0680ba87332dc059146 c |
| 104 | + -d96249ff5d57de5de093e6baff9e0aafa5276a74 d |
| 105 | + |
| 106 | +NOTE: The commit object names shown above would be different for you, but they |
| 107 | +should match the HEAD commit object names of your repositories. You can check |
| 108 | +it by running `git ls-remote ../a`. |
| 109 | + |
| 110 | +Pulling down the submodules is a two-step process. First run `git submodule |
| 111 | +init` to add the submodule repository URLs to `.git/config`: |
| 112 | + |
| 113 | + $ git submodule init |
| 114 | + |
| 115 | +Now use `git-submodule update` to clone the repositories and check out the |
| 116 | +commits specified in the superproject: |
| 117 | + |
| 118 | + $ git submodule update |
| 119 | + $ cd a |
| 120 | + $ ls -a |
| 121 | + . .. .git a.txt |
| 122 | + |
| 123 | +One major difference between `git-submodule update` and `git-submodule add` is |
| 124 | +that `git-submodule update` checks out a specific commit, rather than the tip |
| 125 | +of a branch. It's like checking out a tag: the head is detached, so you're not |
| 126 | +working on a branch. |
| 127 | + |
| 128 | + $ git branch |
| 129 | + * (no branch) |
| 130 | + master |
| 131 | + |
| 132 | +If you want to make a change within a submodule and you have a detached head, |
| 133 | +then you should create or checkout a branch, make your changes, publish the |
| 134 | +change within the submodule, and then update the superproject to reference the |
| 135 | +new commit: |
| 136 | + |
| 137 | + $ git checkout master |
| 138 | + |
| 139 | +or |
| 140 | + |
| 141 | + $ git checkout -b fix-up |
| 142 | + |
| 143 | +then |
| 144 | + |
| 145 | + $ echo "adding a line again" >> a.txt |
| 146 | + $ git commit -a -m "Updated the submodule from within the superproject." |
| 147 | + $ git push |
| 148 | + $ cd .. |
| 149 | + $ git diff |
| 150 | + diff --git a/a b/a |
| 151 | + index d266b98..261dfac 160000 |
| 152 | + --- a/a |
| 153 | + +++ b/a |
| 154 | + @@ -1 +1 @@ |
| 155 | + -Subproject commit d266b9873ad50488163457f025db7cdd9683d88b |
| 156 | + +Subproject commit 261dfac35cb99d380eb966e102c1197139f7fa24 |
| 157 | + $ git add a |
| 158 | + $ git commit -m "Updated submodule a." |
| 159 | + $ git push |
| 160 | + |
| 161 | +You have to run `git submodule update` after `git pull` if you want to update |
| 162 | +submodules, too. |
| 163 | + |
| 164 | +###Pitfalls with submodules |
| 165 | + |
| 166 | +Always publish the submodule change before publishing the change to the |
| 167 | +superproject that references it. If you forget to publish the submodule change, |
| 168 | +others won't be able to clone the repository: |
| 169 | + |
| 170 | + $ cd ~/git/super/a |
| 171 | + $ echo i added another line to this file >> a.txt |
| 172 | + $ git commit -a -m "doing it wrong this time" |
| 173 | + $ cd .. |
| 174 | + $ git add a |
| 175 | + $ git commit -m "Updated submodule a again." |
| 176 | + $ git push |
| 177 | + $ cd ~/git/cloned |
| 178 | + $ git pull |
| 179 | + $ git submodule update |
| 180 | + error: pathspec '261dfac35cb99d380eb966e102c1197139f7fa24' did not match any file(s) known to git. |
| 181 | + Did you forget to 'git add'? |
| 182 | + Unable to checkout '261dfac35cb99d380eb966e102c1197139f7fa24' in submodule path 'a' |
| 183 | + |
| 184 | +You also should not rewind branches in a submodule beyond commits that were |
| 185 | +ever recorded in any superproject. |
| 186 | + |
| 187 | +It's not safe to run `git submodule update` if you've made and committed |
| 188 | +changes within a submodule without checking out a branch first. They will be |
| 189 | +silently overwritten: |
| 190 | + |
| 191 | + $ cat a.txt |
| 192 | + module a |
| 193 | + $ echo line added from private2 >> a.txt |
| 194 | + $ git commit -a -m "line added inside private2" |
| 195 | + $ cd .. |
| 196 | + $ git submodule update |
| 197 | + Submodule path 'a': checked out 'd266b9873ad50488163457f025db7cdd9683d88b' |
| 198 | + $ cd a |
| 199 | + $ cat a.txt |
| 200 | + module a |
| 201 | + |
| 202 | +NOTE: The changes are still visible in the submodule's reflog. |
| 203 | + |
| 204 | +This is not the case if you did not commit your changes. |
0 commit comments