J V J V - 1 year ago 44
Git Question

Git plumbing - find out if there are any unstaged files in a directory quickly

In a bash script I want to know if there are unstaged files in a directory.

The closest I can get is checking the exit code of this:

git ls-files --other --error-unmatch --exclude-standard --directory "$folder/" > /dev/null 2>&1

There are 2 downsides.

  1. I have to use a different command to check if a file is unstaged (Because of the slash)

  2. This will print all the files to
    before exiting, which can take a long time on certain repos

Ideally, I'd like a way for it to stop as soon as it finds an untracked file - I don't need to know what they are, just if they're there

Answer Source

If you're happy with the git command, you can pipe to grep -q, whose return code will tell you if there is any output:

git ls-files --other --exclude-standard --directory "$folder/" | grep -q .

As soon as grep receives any input, the pattern . is matched and it exits sucessfully.

To suppress error output, you can wrap the whole thing in curly braces { } and add 2>/dev/null to the end.

Another option would be to parse the output of git status. For example, to see if any files in the output have a path starting with $directory, you could use this:

git status --porcelain | awk -v dir="$dir" 'index($2, dir) == 1 { found = 1; exit } END { exit !found }'

If your version of awk supports setting the record separator to a null byte, you could use git status -z instead:

git status -z | awk -v RS='\0' -v dir="$dir" 'index($2, dir) == 1 { found = 1; exit } END { exit !found }'

To filter out untracked files, you could add a check for `$1 != "??":

git status -z | awk -v RS='\0' -v dir="$dir" '$1 != "??" && index($2, dir) == 1 { found = 1; exit } END { exit !found }'