tags:

views:

54

answers:

2

In a Makefile, I'd like to perform certain actions if there are uncommited changes (either in the working tree or the index). What's the cleanest and most efficient way to do that? A command that exits with a return value of zero in one case and non-zero in the other would suit my purposes.

I can run git status and pipe the output through grep, but I feel like there must be a better way.

+1  A: 

git diff --exit-code will return nonzero if there are any changes; git diff --quiet is the same with no output. Since you want to check for the working tree and the index, use

git diff --quiet && git diff --cached --quiet

Or

git diff --quiet HEAD

Either one will tell you if there are uncommitted changes that are staged or not.

jleedev
Those are not equivalent. The single command `git diff --quite HEAD` will only tell you whether the working tree is clean, not whether the index is clean. For example, if `file` was changed between HEAD~ and HEAD, then after `git reset HEAD~ -- file`, it will still exit 0 even though there are staged changes present in the index (wt == HEAD, but index != HEAD).
Chris Johnsen
+5  A: 

"Programmatically" means never ever rely on porcelain commands.
Always rely on plumbing commands.

See also "Checking for a dirty index or untracked files with Git" for alternatives (like git status --porcelain)

You can take inspiration from the new "require_clean_work_tree function" which is written as we speak ;) (early October 2010)

require_clean_work_tree () {
    # Update the index
    git update-index -q --ignore-submodules --refresh
    err=0

    # Disallow unstaged changes in the working tree
    if ! git diff-files --quiet --ignore-submodules --
    then
        echo >&2 "cannot $1: you have unstaged changes."
        git diff-files --name-status -r --ignore-submodules -- >&2
        err=1
    fi

    # Disallow uncommitted changes in the index
    if ! git diff-index --cached --quiet HEAD --ignore-submodules --
    then
        echo >&2 "cannot $1: your index contains uncommitted changes."
        git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
        err=1
    fi

    if [ $err = 1 ]
    then
        echo >&2 "Please commit or stash them."
        exit 1
    fi
}
VonC
The "plumbing vs. porcelain for scripting" principle is a lesson that [Jakub Narębski](http://stackoverflow.com/users/46058/jakub-narebski) repeatedly mentioned to me: " [How to list all the log for current project in git ?](http://stackoverflow.com/questions/2978947/how-to-list-all-the-log-for-current-project-in-git/2979124#2979124) ", " [git: changelog day by day](http://stackoverflow.com/questions/2976665/git-changelog-day-by-day/2976776#2976776) ", ...
VonC
After clicking some of the links you suggest, I found what I was looking for: `git diff-index --quiet HEAD`.
Daniel Stutzbach