Git submodules: Specify a branch/tag
git submodule add -b work?
After adding a submodule with a specific branch, a new cloned repo (after
git submodule update --init) will be at a specific commit, not the branch itself (
git status on the submodule shows “Not currently on any branch”).
I can’t find any information on
.git/config about the submodule’s branch or any specific commit, so how does git figure it out?
Also, is it possible to specify a tag instead of a branch?
PS: I’m using
10 Solutions collect form web for “Git submodules: Specify a branch/tag”
Note: Git 1.8.2 added the possibility to track branches. See some of the answers below.
It’s a little confusing to get used to this, but submodules are not on a branch. They are, like you say, just a pointer to a particular commit of the submodule’s repository.
This means, when someone else checks out your repository, or pulls your code, and does git submodule update, the submodule is checked out to that particular commit.
This is great for a submodule that does not change often, because then everyone on the project can have the submodule at the same commit.
If you want to move the submodule to a particular tag:
cd submodule_directory git checkout v1.0 cd .. git add submodule_directory git commit -m "moved submodule to v1.0" git push
Then, another developer who wants to have submodule_directory changed to that tag, does this
git pull git submodule update
git pull changes which commit their submodule directory points to.
git submodule update actually merges in the new code.
I’d like to add an answer here that is really just a conglomerate of other answers, but I think it may be more complete.
You know you have a git submodule when you have these two things.
.gitmodule has an entry like so:
[submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git
2) You have a submodule object (named SubmoduleTestRepo in this example) in your git repository. Github shows these as “submodule” objects. Or do
git submodule status from a command line. Git submodule objects are special kind of git object and they hold the SHA infomation for a specific commit.
Whenever you do a
git submodule update, it will populate your submodule with content from the commit. It knows where to find the commit because of the information in the
Now, all the
-b does is add one line in your
.gitmodule file. So following the same example it would look like this:
[submodule "SubmoduleTestRepo"] path = SubmoduleTestRepo url = https://github.com/jzaccone/SubmoduleTestRepo.git branch = master
EDIT: only branch name is supported above, not SHA or TAG.
The submodule object is still pointing at a specific commit. The only thing that the
-b option buys you is the ability to add a
--remote flag to your update as per Vogella’s answer:
git submodule update --remote
Instead of populating the content of the submodule to the commit pointed to by the submodule, it replaces that commit with the latest commit on the master branch, THEN it populates the submodule with that commit. This can be done in two steps by djacobs7 answer. Since you have now updated the commit the submodule object is pointing to, you have to commit the changed submodule object into your git repository.
git submodule add -b is not some magically way to keep everything up to date with a branch. It is simply adds information about a branch in the
.gitmodule file and gives you the option to update the submodule object to the latest commit of a specified branch before populating it.
Note that if you have an existing submodule which isn’t tracking a branch yet, then (if you have git 1.8.2+):
Make sure the parent repo knows that its submodule now tracks a branch:
cd /path/to/your/parent/repo git config -f .gitmodules submodule.<path>.branch <branch>
Make sure your submodule is actually at the latest of that branch:
cd path/to/your/submodule git checkout -b branch --track origin/branch # if the master branch already exist: git branch -u origin/master master
(with ‘origin’ being the name of the upstream remote repo the submodule has been cloned from.
git remote -v inside that submodule will display it. Usually, it is ‘origin’)
Don’t forget to record the new state of your submodule in your parent repo:
cd /path/to/your/parent/repo git add path/to/your/submodule git commit -m "Make submodule tracking a branch"
Subsequent update for that submodule will have to use the
# update your submodule # --remote will also fetch and ensure that # the latest commit from the branch is used git submodule update --remote # to avoid fetching use git submodule update --remote --no-fetch
Note that with Git 2.10+ (Q3 2016), you can use ‘
.‘ as a branch name:
The name of the branch is recorded as
A special value of
.is used to indicate that the name of the branch in the submodule should be the same name as the current branch in the current repository.
If you want to update all your submodules following a branch:
git submodule update --recursive --remote
Note that the result, for each updated submodule, will always be a detached HEAD, as Dan Cameron note in his answer.
To ensure the branch is actually checked out (and that won’t modify the SHA1 of the special entry representing the submodule for the parent repo), he suggests:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch'
Each submodule will still reference the same SHA1, but if you do make new commits, you will be able to push them because they will be referenced by the branch you want the submodule to track.
After that push within a submodule, don’t forget to go back to the parent repo, add, commit and push the new SHA1 for those modified submodules.
Note the use of
$toplevel, recommended in the comments by Alexander Pogrebnyak.
$toplevel was introduced in git1.7.2 in May 2010: commit f030c96.
it contains the absolute path of the top level directory (where
dtmland adds in the comments:
The foreach script will fail to checkout submodules that are not following a branch.
However, this command gives you both:
git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; [ "$branch" = "" ] && git checkout master || git checkout $branch' –
The same command but easier to read:
git submodule foreach -q --recursive \ 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; \ [ "$branch" = "" ] && \ git checkout master || git checkout $branch' –
umläute refines dtmland’s command with a simplified version in the comments:
git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
git submodule foreach -q --recursive \ 'git checkout \ $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'
Git 1.8.2 added the possibility to track branches.
# add submodule to track master branch git submodule add -b master [URL to Git repo]; # update your submodule git submodule update --remote
See also Git submodules
A example of how I use git submodules.
- Creates a new repo
- Then clones another repo as submodule
- Then we have that submodule use a tag called V3.1.2
- And then we commit
And that looks a little bit like this:
git init vi README git add README git commit git submodule add git://github.com/XXXXX/xxx.yyyy.git stm32_std_lib git status git submodule init git submodule update cd stm32_std_lib/ git reset --hard V3.1.2 cd .. git commit -a git submodule status
maybe it helps? (even thou I use a tag and not a branch)
In my experience switching branches in the superproject or future checkouts will still cause detached HEADs of submodules regardless if the submodule is properly added and tracked (i.e. @djacobs7 and @Johnny Z answers).
And instead of manually checking out the correct branch manually or through a script git submodule foreach can be used.
This will check the submodule config file for the branch property and checkout the set branch.
git submodule foreach -q --recursive 'branch="$(git config -f <path>.gitmodules submodule.$name.branch)"; git checkout $branch'
git submodules are a little bit strange – they’re always in “detached head” mode – they don’t update to the latest commit on a branch like you might expect.
This does make some sense when you think about it, though. Let’s say I create repository foo with submodule bar. I push my changes and tell you to check out commit a7402be from repository foo.
Then imagine that someone commits a change to repo bar before you can make your clone.
When you check out commit a7402be from repo foo, you expect to get the same code I pushed. That’s why submodules don’t update until you tell them to explicitly and then make a new commit.
Personally I think submodules are the most confusing part of git. There are lots of places that can explain submodules better than I can. I recommend Pro Git by Scott Chacon.
I have this in my .gitconfig file. It is still a draft, but proved useful as of now. It helps me to always reattach the submodules to their branch.
[alias] ###################### # #Submodules aliases # ###################### #git sm-trackbranch : places all submodules on their respective branch specified in .gitmodules #This works if submodules are configured to track a branch, i.e if .gitmodules looks like : #[submodule "my-submodule"] # path = my-submodule # url = email@example.com/my-submodule.git # branch = my-branch sm-trackbranch = "! git submodule foreach -q --recursive 'branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; git checkout $branch'" #sm-pullrebase : # - pull --rebase on the master repo # - sm-trackbranch on every submodule # - pull --rebase on each submodule # # Important note : #- have a clean master repo and subrepos before doing this ! #- this is *not* equivalent to getting the last committed # master repo + its submodules: if some submodules are tracking branches # that have evolved since the last commit in the master repo, # they will be using those more recent commits ! # # (Note : On the contrary, git submodule update will stick #to the last committed SHA1 in the master repo) # sm-pullrebase = "! git pull --rebase; git submodule update; git sm-trackbranch ; git submodule foreach 'git pull --rebase' " # git sm-diff will diff the master repo *and* its submodules sm-diff = "! git diff && git submodule foreach 'git diff' " #git sm-push will ask to push also submodules sm-push = push --recurse-submodules=on-demand #git alias : list all aliases #useful in order to learn git syntax alias = "!git config -l | grep alias | cut -c 7-"
To switch branch for a submodule (assuming you already have the submodule as part of the repo):
cdto root of your repo containing the submodules
- Add line below
path = ...and
url = ...that says
branch = your-branch, for each submodule; save file
- then without changing directory do
$ git submodule update --remote
…this should pull in the latest commits on the specified branch, for each submodule thus modified.
We use Quack to pull specific module from other git repository. We need to pull code without whole code base of provided repository – we need very specific module / file from that huge repository and should be updated everytime we run update.
So we achieved in this way,
name: Project Name modules: local/path: repository: https://github.com/<username>/<repo>.git path: repo/path branch: dev other/local/path/filename.txt: repository: https://github.com/<username>/<repo>.git hexsha: 9e3e9642cfea36f4ae216d27df100134920143b9 path: repo/path/filename.txt profiles: init: tasks: ['modules']
With above configuration, it create 1 directory from provided github repository as specified in first module config, and the other one is to pull and create file from given repo.
Other developers just need to run
And it pulls the code from above configurations.