Git has something called submodule support. This allows you to specify one or more other git repositories within another – a bit like svn:externals (except trickier, but more powerful of course :).
The describes submodules but it took me a while to figure it out, so I’m hoping these examples will help others (and me again when I forget and find my own page when googling about it :)
These examples deal with your_project and the project you’ll be adding as a submodule, other_project
Adding a submodule to your_project $ git submodule add git@git.example.com:other_project.git other_project
Initialized empty Git repository in /home/john/dev/your_project/other_project/.git/
remote: Counting objects: 59, done.
remote: Compressing objects: 100% (59/59), done.
remote: Total 59 (delta 22), reused 0 (delta 0)
Receiving objects: 100% (59/59), 8.33 KiB, done.
Resolving deltas: 100% (22/22), done.
This clones other_project and sets up the .gitmodules config to your_project and adds them both ready to be committed. You’ll notice that the other_project directory is added, not all the files within. Git just records the commit id from the other_project repository and uses that when cloning – a bit like a tag.
$ git status# new file: .gitmodules
# new file: other_project
So now commit those changes:
$ git commit .gitmodules other_project -m "Added other_project submodule"$ git push
Cloning a tree with submodules
Git doesn’t automatically fetch all your submodules, so you need to do the following after cloning your tree:
$ git submodule initSubmodule 'other_project' (git@git.example.com:other_project.git) registered for path 'other_project'
$ git submodule update
Initialized empty Git repository in /home/john/dev/your_project/other_project/.git/
remote: Counting objects: 59, done.
Receiving objects: 100% (59/59), 8.33 KiB, done.bjects: 91% (54/59)
Resolving deltas: 100% (22/22), done.
remote: Compressing objects: 100% (59/59), done.
remote: Total 59 (delta 22), reused 0 (delta 0)
Submodule path 'other_project': checked out '6d5ca374208715501832eb33ed6a70022a3bb60c'
Updating a submodule
So somebody pushed some updates to other_project and you want them in your_project:
$ cd other_project$ git pull origin master
Updating 6d5ca37..235996d
Fast forward
5 files changed, 100 insertions(+), 10 deletions(-)
$ cd ..
$ git add other_project
$ git commit otherproject -m " Updated other_project submodule to latest HEAD"
If you want a particular commit rather than the head of master, then just specify that commit id on pull (instead of master). If you want the head of a particular branch then specify that branch name instead of master.
It is important not to have a trailing slash when you add other_project as this will treat it as a normal directory, adding all the files within it to your_project and forgetting about it’s submodule status
Making changes to a submodule within your_projectTo make changes to other_project within your_project tree, you need to explicitly checkout a branch first:
$ cd other_project$ git checkout master
...make your changes...
$ git commit -a -m "Fixed a bug"
$ git push
$ cd ..
$ git add other_project
$ git commit -m "Updated other_project"
You need to remember to push changes to other_project before you push your_project else others won’t be able to clone your_project properly as it will reference commits to other_project that haven’t been published yet!