1086

How does git submodule add -b work?

After adding a submodule with a specific branch, a new cloned repository (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 .gitmodules or .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?

I'm using version 1.6.5.2.

Ivan
  • 97,549
  • 17
  • 50
  • 58
  • 5
    If you have an **existing** submodule which **isn't tracking a branch yet**, but you wish it now would track a branch... [see my answer below](http://stackoverflow.com/a/18799234/6309) – VonC Sep 14 '13 at 07:00
  • 2
    it seems I can specify the branch in the `.gitmodules` file but when I do `git submodule update` and variants (e.g. --all, --recursive, etc) it doesn't pull the git submodule to the right branch. This is obvious rom the `git submodule status`. How do I pull and make sure it's in the right branch? Otherwise what is the point of specifying the branch then? – Charlie Parker Jan 03 '23 at 00:44

14 Answers14

1066

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.

  1. Your .gitmodules 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 kinds of Git objects, and they hold the SHA information 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 .gitmodules.

    Now, all the -b does is add one line in your .gitmodules file. So following the same example, it would look like this:

    [submodule "SubmoduleTestRepo"]
        path = SubmoduleTestRepo
        url = https://github.com/jzaccone/SubmoduleTestRepo.git
        branch = master
    

    Note: only branch name is supported in a .gitmodules file, but SHA and TAG are not supported! (instead of that, the branch's commit of each module can be tracked and updated using "git add .", for example like git add ./SubmoduleTestRepo, and you do not need to change the .gitmodules file each time)

    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 .gitmodules file and gives you the option to update the submodule object to the latest commit of a specified branch before populating it.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Johnny Z
  • 14,329
  • 4
  • 28
  • 35
  • 24
    Does this branch tracking also work with **tags**? Instead of a branch I specified a tag in my `.gitmodules` and after doing `$ git submodule update --init --remote TestModule` I got an error saying `fatal: Needed a single revision` and `Unable to find current origin/TestTag revision in submodule path 'TestModule'`. When doing it with a real branch it works. Is there anyway to specify a tag in `.gitmodules` without having to specify the exact commit? – Hhut Sep 04 '15 at 08:19
  • 2
    @JohnnyZ, You mentioned the info for the specific commit to track is from the .gitmodules file. But I think the SHA of the commit is actually comes from `.git/modules//HEAD` IIRC. – Sid Dec 08 '15 at 17:39
  • 10
    This doesn't seem to work. I updated the hash in `.gitmodules` and ran `git submodule update` and nothing happened? – CMCDragonkai Apr 04 '16 at 14:17
  • 2
    @CMCDragonkai : you have to sync the url by doing git submodule sync for the changes to get effective. – infoclogged Jun 29 '16 at 15:18
  • 3
    Somehow this doesnt work for me. With a SHA Commit Id, I always get an error "Unable to find current revision ( I double checked the revision number of HEAD and its correct ) . However if I use master it works. – infoclogged Jun 29 '16 at 15:27
  • When cloning a repository that contains submodules (that were added using "git submodule add -b") I get the most current commits for the submodules automatically; is that correct? – Silicomancer Mar 08 '17 at 00:01
  • 3
    Entering a SHA into the branch attribute doesn't work for me either. This usage is also *not* supported by the docs: https://git-scm.com/docs/gitmodules – Jakub Bochenski Jun 28 '17 at 14:44
  • _"`git submodule add -b` ... simply ... gives you the option to update the submodule object to the latest commit of a specified branch"_ Wait a second. Doesn't it instruct `git` to rather look for the commit on that branch instead of the default one as per https://superuser.com/questions/1240216/what-does-the-git-error-message-server-does-not-allow-request-for-unadvertised/1286550#1286550 ? https://git-scm.com/docs/gitmodules#gitmodules-submoduleltnamegtbranch suggests as much. – ivan_pozdeev Jan 21 '18 at 01:14
  • This was so simple and worked as it should. I added this line into my .gitmodule and the bash script for the docker environment I've written pulled the latest master branch down. Excellent documentation. – Jason Glisson Apr 18 '18 at 13:22
  • 1
    This is great. When running `git submodule update --init --recursive --remote` I always received error `Unable to find current origin/master revision` because the primary repo had default branch `master` and my submodules have `main`. Adding `branch = main` to `.gitmodules` where needed did the trick. – plong0 Aug 26 '21 at 00:00
  • 2
    I think this may be a little confusing and might have led to people trying to add a SHA1 value to `.gitmodules`: "_Whenever you do a git submodule update. . .It knows where to find the commit because of the information in the .gitmodules._" (As stated in the same answer) the `.gitmodules` file doesn't give a **commit** for the submodule. The actual commit (SHA1) lives not inside the `.gitmodules` file, but inside the containing repo's `.git/modules/` folder (here, `.git/modules/SubmoduleTestRepo/`). More details: https://stackoverflow.com/questions/10914022/. [Ah, @Sid already said it.] – M.Bearden Feb 02 '22 at 17:35
  • 3
    tldr: to lock tag: cd into that submodule, checkout the tag; commit. – zrfrank Jun 06 '22 at 21:04
  • it seems I can specify the branch in the `.gitmodules` file but when I do `git submodule update` and variants (e.g. --all, --recursive, etc) it doesn't pull the git submodule to the right branch. This is obvious rom the `git submodule status`. How do I pull and make sure it's in the right branch? Otherwise what is the point of specifying the branch then? – Charlie Parker Jan 03 '23 at 00:44
945

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 --init

git pull changes which commit their submodule directory points to. git submodule update actually merges in the new code.

djacobs7
  • 11,357
  • 3
  • 25
  • 33
  • 16
    That's a very good explanation, thanks! And of course, after reading your answer, I realized the commit is saved inside the submodule itself (submodule/.git/HEAD). – Ivan Nov 22 '09 at 18:19
  • Is it possible to achieve something like svn branching but with submodules ? In svn you can create a branch and then merge that with the trunk ( and possibly also with other existing branches). Then you can merge all of them with the trunk. Is something like this possible, but with Git submodules ? – mjs Dec 01 '11 at 12:41
  • 6
    This doesn't seem to work on git 1.7.4.4. `cd my_submodule; git checkout [ref in submodule's repository` yields `fatal: reference is not a tree: ...`. It's as if `git` will only operate on the parent repository. – James A. Rosen May 04 '12 at 21:12
  • 4
    It's good to use git submodules even for projects that are updated often. The linux kernel uses it and it isn't so bad –  Apr 30 '13 at 18:15
  • Annoying thing for me at the moment is, that when I switch project branch, it doesn't automatically switch submodule/s branche/s. Till now I had to do it manually. Will try suggested way in @vogella answer. – Eugene Jul 20 '14 at 12:19
  • 15
    Is `git checkout v1.0` a branch or a tag? – Bernhard Döbler Oct 01 '15 at 22:30
  • 13
    Consider a tag a human readable alias to a commit. And a commit is a set of specific state for each file. A branch is essentially the same thing except you can make changes to it. – deadbabykitten Feb 02 '16 at 00:13
  • 3
    Note: the remote must be in the form git:// And using http will cause failures. It took me a while to realize that I was not using the correct protocol. – Igor Stoppa Nov 11 '16 at 23:09
  • 2
    Thank you for your answer, but it doesn't work. It's not adding the folder to changes to be commited. – w00tland Sep 18 '18 at 13:52
  • 1
    @BernhardDöbler it's a tag. – Blind0ne Aug 30 '19 at 12:03
  • it seems I can specify the branch in the `.gitmodules` file but when I do `git submodule update` and variants (e.g. --all, --recursive, etc) it doesn't pull the git submodule to the right branch. This is obvious rom the `git submodule status`. How do I pull and make sure it's in the right branch? Otherwise what is the point of specifying the branch then? – Charlie Parker Jan 03 '23 at 00:44
471

(Git 2.22, Q2 2019, has introduced git submodule set-branch --branch aBranch -- <submodule_path>)

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 branch already exist:
        git branch -u origin/branch branch
    

         (with 'origin' being the name of the upstream remote repo the submodule has been cloned from.
         A 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 --remote option:

      # 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 
    

Lolorol suggests in the comments to set the branch in each submodule:

git submodule update --init --recursive
git submodule foreach -q --recursive \
  'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git switch ${branch}'
git submodule

Note that with Git 2.10+ (Q3 2016), you can use '.' as a branch name:

The name of the branch is recorded as submodule.<name>.branch in .gitmodules for update --remote.
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.

But, as commented by LubosD

With git checkout, if the branch name to follow is ".", it will kill your uncommitted work!
Use git switch instead.

That means Git 2.23 (August 2019) or more.

See "Confused by git checkout"


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 almost always be a detached HEAD, as Dan Cameron note in his answer.

(Clintm notes in the comments that, if you run git submodule update --remote and the resulting sha1 is the same as the branch the submodule is currently on, it won't do anything and leave the submodule still "on that branch" and not in detached head state.)

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 switch $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 .gitmodules is).

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 switch $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 switch $branch' –
  

umläute refines dtmland's command with a simplified version in the comments:

git submodule foreach -q --recursive 'git switch $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

multiple lines:

git submodule foreach -q --recursive \
  'git switch \
  $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'

Before Git 2.26 (Q1 2020), a fetch that is told to recursively fetch updates in submodules inevitably produces reams of output, and it becomes hard to spot error messages.

The command has been taught to enumerate submodules that had errors at the end of the operation.

See commit 0222540 (16 Jan 2020) by Emily Shaffer (nasamuffin).
(Merged by Junio C Hamano -- gitster -- in commit b5c71cc, 05 Feb 2020)

fetch: emphasize failure during submodule fetch

Signed-off-by: Emily Shaffer

In cases when a submodule fetch fails when there are many submodules, the error from the lone failing submodule fetch is buried under activity on the other submodules if more than one fetch fell back on fetch-by-oid.
Call out a failure late so the user is aware that something went wrong, and where.

Because fetch_finish() is only called synchronously by run_processes_parallel, mutexing is not required around submodules_with_errors.


Note that, with Git 2.28 (Q3 2020), Rewrite of parts of the scripted "git submodule" Porcelain command continues; this time it is "git submodule set-branch" subcommand's turn.

See commit 2964d6e (02 Jun 2020) by Shourya Shukla (periperidip).
(Merged by Junio C Hamano -- gitster -- in commit 1046282, 25 Jun 2020)

submodule: port subcommand 'set-branch' from shell to C

Mentored-by: Christian Couder
Mentored-by: Kaartic Sivaraam
Helped-by: Denton Liu
Helped-by: Eric Sunshine
Helped-by: Đoàn Trần Công Danh
Signed-off-by: Shourya Shukla

Convert submodule subcommand 'set-branch' to a builtin and call it via git submodule.sh.

E. Douglas
  • 234
  • 1
  • 3
  • 11
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 2
    Question: if i have folder subModule1 and wish to track master branch, would the resulting command look like this: **git config -f .gitmodules submodule.subModule1.branch master** – BraveNewMath Sep 17 '13 at 20:41
  • @BraveNewMath If your submodule is directly under the root of your parent repo, then yes, since it represetns its path within the parent repo: `submodule..branch`. But don't forget the other steps. – VonC Sep 17 '13 at 20:53
  • 2
    here's a simplified version of @dtmland's script: `git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master)'` – umläute Oct 15 '15 at 11:54
  • @umläute good point. I have included your comment in the answer for more visibility. – VonC Oct 15 '15 at 16:39
  • This command does not merge (or rebase) origin/ to local . So we have to add `git pull` to the script: `git submodule foreach -q --recursive 'git checkout $(git config -f $toplevel/.gitmodules submodule.$name.branch || echo master); git pull'` At least for me this is the working script. – GregTom Apr 17 '17 at 03:51
  • 1
    Ohh! Actually the foreach script is unnecessary. We have to execute the submodule update with the --merge or --rebase switch: `git submodule update --remote --merge` or `git submodule update --remote --rebase`. These commands do the tracking of the remote branch. – GregTom Apr 17 '17 at 04:16
  • @VonC Is it really safe to assume the branch to be 'master' if not specified in the .gitmodules file? I tried running 'git remote -v' in few such submodules with branch info missing and though they seems to have a detached HEAD but the branch they detached from was not always 'master'. – sactiw Dec 14 '17 at 07:48
  • @sactiw yes, see (and skip to) the conclusion part of the very long answer https://stackoverflow.com/a/37924157/6309: "defaulting to master when no `submodule..` is found.". A detached HEAD does not reference a branch. It can be part of different branches, included master. – VonC Dec 14 '17 at 09:02
  • These last two comments don't change the fact that after a clone and initial "git submodule update --init --remote", the submodule will show up as "detached HEAD." – MrMas Oct 25 '19 at 20:21
  • Oh, my god! Why git makes the submodule designing logics so complex? I've used VCS for about 20 years, but still can't fully know how to use this git submodule? What we need is very simple: how to config the submodule to follow a branch? And when the branch's head progressed, the super project&submodule should follow it. – Clock ZHONG Dec 25 '21 at 17:28
  • 1
    @ClockZHONG `git config -f .gitmodules submodule..branch ` and `git submodule update --remote` should be enough. – VonC Dec 25 '21 at 17:36
  • it seems I can specify the branch in the `.gitmodules` file but when I do `git submodule update` and variants (e.g. --all, --recursive, etc) it doesn't pull the git submodule to the right branch. This is obvious rom the `git submodule status`. How do I pull and make sure it's in the right branch? Otherwise what is the point of specifying the branch then? – Charlie Parker Jan 03 '23 at 00:44
  • @CharlieParker It is best to ask a separate question, but first, did you do a `git config -f .gitmodules submodule..branch ` *and*, from *within* the submodule folder, a `git switch -c --track /`? – VonC Jan 03 '23 at 00:48
  • @VonC that won't scale if I have hundreds of submodules. I specified it in my gitmodules file. Why doesn't the update use the specification I said there? Why do I need to specify it twice? – Charlie Parker Jan 03 '23 at 00:54
  • https://stackoverflow.com/questions/74988223/why-do-i-need-to-add-the-remote-to-gits-submodule-when-i-specify-the-branch – Charlie Parker Jan 03 '23 at 00:54
  • One of the scenario that was not covered with the solution above was to re-create the submodule path. `git submodule update --init --recursive; git submodule foreach -q --recursive 'branch="$(git config -f $toplevel/.gitmodules submodule.$name.branch)"; git checkout $branch'; git submodule` – Lolorol Mar 21 '23 at 08:21
314

Git 1.8.2 added the possibility to track branches.

# add submodule to track branch_name branch
git submodule add -b branch_name URL_to_Git_repo optional_directory_rename

# update your submodule
git submodule update --remote 

See also Git submodules

DDS
  • 2,340
  • 16
  • 34
vogella
  • 24,574
  • 4
  • 29
  • 26
  • 15
    Does this apply to tags as well? – ThorSummoner Jul 02 '14 at 21:28
  • There is no use for tracking a tag as it's supposed to be a fixed point in code. For locking at a tag see djacobs7 's [answer](http://stackoverflow.com/a/1778247/1023341). - @ThorSummoner – gkephorus Jul 09 '14 at 06:19
  • 1
    How does adding submodule in such way reflect on `.gitmodules` file? – Eugene Jul 20 '14 at 12:22
  • 2
    Thanks I just used the info about to help me to create a submodule folder that is synced with a GitHub gh-pages website: full example at https://github.com/o2platform/fluentnode/issues/22 – Dinis Cruz Dec 24 '14 at 02:03
  • 15
    You can lock to a *tag* with `git submodule add -b tags/ ` which you can see as the line `branch = tags/` in `.gitmodules` – KCD Oct 16 '15 at 02:27
  • 16
    @KCD Which version of git can do that with tags. Mine doesn't work? – CMCDragonkai Apr 04 '16 at 13:56
  • @vogella Link migrated to https://www.vogella.com/tutorials/GitSubmodules/article.html – Den Drobiazko Dec 13 '19 at 14:53
  • it seems I can specify the branch in the `.gitmodules` file but when I do `git submodule update` and variants (e.g. --all, --recursive, etc) it doesn't pull the git submodule to the right branch. This is obvious rom the `git submodule status`. How do I pull and make sure it's in the right branch? Otherwise what is the point of specifying the branch then? – Charlie Parker Jan 03 '23 at 00:44
75

An example of how I use Git submodules.

  1. Create a new repository
  2. Then clone another repository as a submodule
  3. Then we have that submodule use a tag called V3.1.2
  4. 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 though I use a tag and not a branch)?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Johan
  • 20,067
  • 28
  • 92
  • 110
  • 1
    Should you be able to commit a change after your `git reset --hard V3.1.2`? I just get a "nothing to commit" with a `git status` of the parent directory. – Nick Radford Oct 10 '12 at 20:07
  • 1
    @Ivan: Could you explain how this is the same as djacobs7's response? As far as I see, his response doesn't even include the 'submodule add' command, instead the repo is added directly, without any link to the module's original git repo. At least when I tried this approach there was no link in .gitmodules. – Michel Müller Aug 12 '13 at 08:14
  • djacobs7's response doesn't include the whole explanation starting from adding the submodule. He assumes you already have it. – CodeMonkey Aug 22 '17 at 06:04
  • doesn't it just add the entire submodule contents as tracked objects to your main repo? – Sergey Grechin Apr 30 '20 at 07:58
49

Existing answers have the second step missing and overloaded with details.

To switch an existing submodule to track a new remote url and/or a new branch:

  1. Edit the source of truth in .gitmodules.

For example, from

[submodule "api"]
    path = api
    url = https://github.com/<original_repo>/api.git

to

[submodule "api"]
    path = api
    url = https://github.com/<another_repo>/api.git
    branch = work-in-progress

You can also use hexsha for a commit hash. Or tag, but see 3.

  1. git submodule sync: Updates the description of submodules cached by git in .git/modules from the just-edited source of truth specified in .gitmodules.

  2. Only if you specify a tag: git submodule foreach --recursive 'git fetch --tags' to fetch tags.

  3. git submodule update --init --recursive --remote: Updates the checked-out submodules in the working copy.

  4. Commit the changes.

Dmitry Spikhalskiy
  • 5,379
  • 1
  • 26
  • 40
43

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 repository bar before you can make your clone.

When you check out commit a7402be from repository 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Neall
  • 26,428
  • 5
  • 49
  • 48
  • Sorry, but you didn't clarify if one would get the same as you pushed to a7402be , or get the latest of bar, though your version of foo. Thanks :) – mjs Dec 01 '11 at 12:44
  • 7
    The issue is that there should be an option to say "keep this submodule on branch X" so that if you WANT it to automatically update itself then you can make that happen. It would make submodules much more useful for managing e.g. a WordPress installation where plugins are all Git repos without having to re-save the superproject for every plugin that updates. – jerclarke Oct 25 '12 at 18:23
  • @jeremyclark ```git clone git://github.com/git/git.git``` and push that feature...? =D – Alastair Nov 07 '12 at 04:01
  • @0xC0000022L That is because getting the finger from `git` 10000000 times a day is still preferrable to the beastiality other versioning tools deem sensible. – user1129682 Sep 02 '19 at 10:55
  • @user1129682 hmm, "well" spoken. Except you failed to mention of what nature that "beastiality" (sic!) could possibly be or even which particular "versioning tools" you even mean. – 0xC0000022L Sep 02 '19 at 12:30
43

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 $toplevel.gitmodules submodule.$name.branch)"; git checkout $branch'

Diogo Cardoso
  • 21,637
  • 26
  • 100
  • 138
Dan Cameron
  • 756
  • 6
  • 8
25

To switch branch for a submodule (assuming you already have the submodule as part of the repository):

  • cd to root of your repository containing the submodules
  • Open .gitmodules for editing
  • Add line below path = ... and url = ... that says branch = your-branch, for each submodule; save file .gitmodules.
  • 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Engineer
  • 8,529
  • 7
  • 65
  • 105
16

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 = git@wherever.you.like/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-"
Lucas
  • 523
  • 2
  • 10
  • 20
Pascal T.
  • 3,866
  • 4
  • 33
  • 36
4

We use Quack to pull a specific module from another Git repository. We need to pull code without the whole code base of the provided repository - we need a very specific module / file from that huge repository and should be updated every time we run update.

So we achieved it in this way:

Create configuration

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 the above configuration, it creates one directory from the provided GitHub repository as specified in first module configuration, and the other one is to pull and create a file from the given repository.

Other developers just need to run

$ quack

And it pulls the code from the above configurations.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Love Sharma
  • 1,981
  • 1
  • 18
  • 37
4

The only effect of choosing a branch for a submodule is that, whenever you pass the --remote option in the git submodule update command line, Git will check out in detached HEAD mode (if the default --checkout behavior is selected) the latest commit of that selected remote branch.

You must be particularly careful when using this remote branch tracking feature for Git submodules if you work with shallow clones of submodules. The branch you choose for this purpose in submodule settings IS NOT the one that will be cloned during git submodule update --remote. If you pass also the --depth parameter and you do not instruct Git about which branch you want to clone -- and actually you cannot in the git submodule update command line!! -- , it will implicitly behave like explained in the git-clone(1) documentation for git clone --single-branch when the explicit --branch parameter is missing, and therefore it will clone the primary branch only.

With no surprise, after the clone stage performed by the git submodule update command, it will finally try to check out the latest commit for the remote branch you previously set up for the submodule, and, if this is not the primary one, it is not part of your local shallow clone, and therefore it will fail with

fatal: Needed a single revision

Unable to find current origin/NotThePrimaryBranch revision in submodule path 'mySubmodule'

Community
  • 1
  • 1
LuKePicci
  • 51
  • 3
3

git submodule add -b develop --name branch-name -- https://branch.git

wovano
  • 4,543
  • 5
  • 22
  • 49
Passiondroid
  • 1,573
  • 1
  • 16
  • 28
-2

Use the below commands

To add submodule (branch-branch)

git submodule add -b stage git@github.optum.com:orgname/${reponame}.git

Update Submodule (branch-branch)

######Clone########

> git clone -b master --single-branch --recurse-submodules git@github.com:orgname/project.git  
or  
> git clone -b stage --single-branch --recurse-submodules git@github.com:orgname/project.git

######Update#######
> git submodule update  --remote (only for remote branch -ie master) 
or 
> git submodule update --recursive --remote

> git submodule update --init --recursive (for remaining branchs)

if you get fatal need single revision error then use below commands:-

before:-

*** stage
  remotes/origin/stage**

git branch -a

git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/{branch name}
ex:- git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/stage

after:-
*** stage
  remotes/origin/HEAD -> origin/stage
  remotes/origin/stage**

then 

> git reset --hard

#hard reset revisions#

> git submodule foreach git reset --hard origin/develop

> git submodule foreach git pull origin develop

after commit and push accordingly.. now submodules will get updated.