Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

My indention is to have a script that updates all git submodules according to which branch is given. If there's no such branch for a submodule, master is used.

This is what I have now:

#!/bin/bash -x

if [ -z $1 ]; then
    echo "Branch name required."

function pbranch {
    exists=`git show-ref refs/heads/$branch`

    if [ -z $exists ]; then

    git co $branch
    git pull origin $branch


git submodule foreach pbranch

But when running this script, the error is thrown:

oleq@pc ~/project> git-fetchmodules major
+ '[' -z major ']'
+ branch=major
+ git submodule foreach pbranch
Entering 'submodule'
/usr/lib/git-core/git-submodule: 1: eval: pbranch: not found
Stopping at 'submodule'; script returned non-zero status.

My guess is that git submodule foreach utilizes eval (according to the documentation), which I don't use correctly in this context.

There are billions of examples of how to use this command with "inline callback" but I couldn't found a single one with the callback in form of the function. Any idea how to solve this?

share|improve this question

A shell function only exists inside the shell where it is defined. Similarly, a Java method only exists in the program instance where it is defined, and so on. You cannot invoke a shell function from another program, even if that program happens to be another shell that is run by a child process of the original shell.

Instead of defining a function, make pbranch a separate script. Put it in your PATH.

ref="$(git show-ref "refs/heads/$branch")"
if [ -z "$ref" ]; then
git co "$branch"
git pull origin "$branch"

Shell programming note: always put double quotes around variable substitutions and command substitutions: "$foo", "$(foo)", unless you know that you need to leave the quotes out. Unprotected substitutions are interpreted as whitespace-separated lists of glob patterns, which is almost never desired. Also, don't use backticks, for similar reasons, use $(…) instead. Here, it doesn't actually matter because git branch names don't contain special characters, and because [ -z $branch ] is parsed as [ -z ] which is also true when branch is empty. But don't get into the habit of omitting the quotes, it will come back and bite you.

Let's say the script is called pbranch-submodule, you can then run

git submodule foreach pbranch-submodule
share|improve this answer
And if you name it git-pbranch-submodule, it can behave like a built-in git command: git pbranch-submodule or git submodule foreach git pbranch-submodule. (Note that foreach accepts a shell command and not a git command.) – idbrii Aug 1 '14 at 13:12
up vote 2 down vote accepted

I resolved my issue by putting the function inside of the quotes as a callback:


if [ -z $1 ]; then
    echo "Branch name required."

git submodule foreach "
    exists=\$(git show-ref refs/heads/\$branch | cut -d ' ' -f1);

    if [ -z \$exists ]; then

    echo Checking branch \$branch for submodule \$name.;

    git fetch --all -p;
    git co \$branch;
    git reset --hard origin/\$branch;

Note that variables like $1 are those from the script's namespace. The "escaped ones" like $\(bar), \$branch are evaluated within "the callback". It was pretty easy.

share|improve this answer

You can use functions, but you need to export them first:

export -f pbranch

Also, if you want bash syntax extensions, you might want to force a bash shell to be started:

git submodule foreach bash -c 'pbranch'
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.