J V
J V

Reputation: 11936

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 /dev/null 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

Upvotes: 2

Views: 365

Answers (2)

aragaer
aragaer

Reputation: 17848

Not sure if it is faster or slower, but git clean -n would list unstaged files.

This doesn't solve the problem of "stop as soon as first unstaged file" is found, but it seems that there is no good way to do that.

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74595

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 }'

Upvotes: 2

Related Questions