views:

121

answers:

3

Hi! How can I check, in a script, if local changes are present? Perhaps in combination with git describe?

A: 

git status exits with non-zero status if there is no local changes.

But I don't understand what you mean "in combination with git describe".

Iamamac
v1.1-5-g1234567 would mean no local changes and v1.1-5-g1234567(+) would mean with local changes. git status returned 1 here when unstaged local changes were present
Adrian Panasiuk
+1  A: 

git diff --quiet returns with exit status 1 if there're changes and 0 if there're not.

Keep in mind that it will show diff between staged changes and the working dir. If you're interested in changes between your HEAD and working dir, you should use git diff HEAD --quiet.

--quiet implies --exit-code.

Antony Hatchkins
I see two problems with this solution: a) `git diff` is porcelain, and git upstream strongly recommend against using porcelain in scripts. b) `git diff` will ignore any uncommitted changes already in the index cache.See my answer at http://stackoverflow.com/questions/1985301/how-to-make-git-describe-mention-the-presence-or-absence-of-local-changes/1989142#1989142 for how to address these issues.
ndim
The question was about finding _local changes_. `git diff HEAD --quiet` finds _local changes_ being exactly the result of two plumbing commands you have advised. The difference between porcelain/plumbing is not so crucial here.
Antony Hatchkins
The git devs say to use plumbing commands for scripts, so I base my scripts on those. As to the *local changes*, `git diff HEAD --quiet` is certainly functionally equivalent to my two commands, but I would still prefer the API git upstream recommend for scripting cases.
ndim
I wouldn't treat git devs general advice to use plumbing in scripts so punctiliously. I can't imagine any use of git --quiet other than in a script, which indicates that _this_ very subcommand with _this_ option is an exception from the rule. And yes, parsing the results of git diff (without --quiet) in a script would surely be error-prone.
Antony Hatchkins
+1  A: 

You will need to make sure that both the two following properties are met:

  1. That there are no differences between HEAD and the index cache

    git diff-index --cached HEAD

  2. That there are no differences between the index and the working tree:

    git diff-files

Both commands take a --quiet parameter which will set the exit code according to whether there are differences or not (starting some time after git 1.4). If you need to make it work on git 1.4, you need to run the commands without --quiet and check whether they produce any output.

Note: git diff is a porcelain command, and thus should not be used in scripts. Use above plumbing commands instead.

Example shell code, taken from my git_version.sh script:

git_dirty=yes
# git-1.4 does not understand "git-diff-files --quiet"
# git-1.4 does not understand "git-diff-index --cached --quiet HEAD"
if [ "x$($GIT diff-files)" = "x" ] && [ "x$($GIT diff-index --cached HEAD)" = "x" ]; then
    git_dirty=no
fi

If you can require a git version >= 1.5, if git diff-files --quiet && git diff-index --quiet --cached HEAD; then can replace above comparison.

Note: This solution (exactly like Antony's interactive git diff HEAD --quiet) only discovers local changes relative to HEAD. However, local commits can arguable also be considered local changes, and naturally will not show up in any diff against HEAD. You will need to check the SHA1 value git describe uses to detect whether HEAD is from a set of commits you consider not to be local changes.

ndim
See also my comments at http://stackoverflow.com/questions/1985301/how-to-make-git-describe-mention-the-presence-or-absence-of-local-changes/1985431#1985431
Antony Hatchkins