How can I check in a Bash script if my local Git repository has changes?

This works too:

if [ $(git status --porcelain | wc -l) -eq "0" ]; then
  echo "  🟢 Git repo is clean."
else
  echo "  🔴 Git repo dirty. Quit."
  exit 1
fi

Using git status:

cd /git/directory
if [[ `git status --porcelain` ]]; then
  # Changes
else
  # No changes
fi

Although Jefromi's answer is good, I'm posting this just for reference.

From the Git source code there is a sh script which includes the following.

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}

What you're doing will almost work: you should quote $CHANGED in case it's empty, and -z tests for empty, which means no changes. What you meant was:

if [ -n "$CHANGED" ]; then
    VN="$VN-mod"
fi

A quote from Git's GIT-VERSION-GEN:

git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty"

It looks like you were copying that, but you just forgot that detail of quoting.

Of course, you could also just do this:

if git diff-index --quiet HEAD --; then
    # No changes
else
    # Changes
fi

Or if you only care about the "something has changed" case:

if ! git diff-index --quiet HEAD --; then
    VN="$VN-mod"
fi

Using --quiet has the benefit that Git can stop processing as soon as it encounters a single diff, so it may not have to check your entire work tree.

Tags:

Git