Question: The goal is to get an unambiguous status that can be evaluated in a shell command.

I tried `git status` but it always returns 0, even if there are items to commit.

```bash
git status
echo $?  #this is always 0

```

I have an idea but I think it is rather a bad idea.

```bash
if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

```

any other way?

---

**update with following solve, see Mark Longair's post**

I tried this but it causes a problem.

```bash
if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

```

I get the following error `[: ??: binary operator expected`

now, I am looking at the man and try the git diff.

===================code for my hope, and hope better answer======================

```bash
#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi

```

Answer: 
An alternative to testing whether the output of `git status --porcelain` is empty is to test each condition you care about separately. One might not always care, for example, if there are untracked files in the output of `git status`.

For example, to see if there are any local unstaged changes, you can look at the return code of:

```
git diff --exit-code

```

To check if there are any changes that are staged but not committed, you can use the return code of:

```
git diff --cached --exit-code

```

Finally, if you want to know about whether there are any untracked files in your working tree that aren't ignored, you can test whether the output of the following command is empty:

```
git ls-files --other --exclude-standard --directory

```

*Update:* You ask below whether you can change that command to exclude the directories in the output. You can exclude empty directories by adding `--no-empty-directory`, but to exclude all directories in that output I think you'll have to filter the output, such as with:

```
git ls-files --other --exclude-standard --directory | egrep -v '/$'

```

The `-v` to `egrep` means to only output lines that don't match the pattern, and the pattern matches any line that ends with a `/`.
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
}

```

This sniplet shows how its possible to use `git diff-files` and `git diff-index` to find out if there are any changes to previously known files. It does not however allow you to find out if a new unknown file has been added to the working tree.