'git: Find all uncommitted locals repos in a directory tree

I have a bunch(10-15) of local git repositories somewhere on my filesystem, but all in the folder /data/

I want to find all/any folder that has uncommitted changes. How can I do that? Kind of like a recursive global git status variant.

All the answers got it wrong I think. Any git command only works within the folder that's under git control. I need something to search for such folders.

So instead I wrote this script that does this:

#!/usr/bin/env ruby
require 'find'
require 'fileutils'

#supply directory to search in as argument

@pat = ARGV[0]
(puts "directory argument required"; exit) unless @pat
Dir.chdir(@pat)
Find.find(@pat) do |path|
  if FileTest.directory?(path)
    Dir.chdir(path)
    resp = `git status 2>&1`
    unless resp =~ /fatal|nothing to commit \(working directory clean\)/i
      puts "#{'#'*10}\n#{Dir.pwd}#{'#'*10}\n#{resp}"
      Find.prune
    end

    Dir.chdir(@pat)
  end
end


Solution 1:[1]

Adapted from this gist on how to print git status of all repositories under the current folder:

find . -type d -name '.git' | while read dir ; do sh -c "cd $dir/../ && echo -e \"\nGIT STATUS IN ${dir//\.git/}\" && git status -s" ; done

The find command is your friend, along with some shell magic.

Solution 2:[2]

I don't think git has this build in, thus I (also) created a script to do this: https://github.com/mnagel/clustergit

The problem with the snippets posted here is that they break as the output format of git status changes. My script has the same problem (as it basically works the same way), but at least you always get the latest version. enter image description here

Solution 3:[3]

Something along these lines?

$ for i in /data/*/; do (cd $i && (echo $i; git status)); done
$ for i in /data/*/; do (cd $i \
> && (git status | grep -qx 'nothing to commit (working directory clean)' \
> || (echo $i && git status))); done

Solution 4:[4]

There is also a shell script called multi-git-status that does this.

Simply use the mgitstatus command (with an optional directory name argument):

Solution 5:[5]

I think this will do the job for each repo

git status -uall

https://git-scm.com/docs/git-status

Solution 6:[6]

Using only find

There's really no need for fancy bash tomfoolery, just use find.

find . -type d -name .git -print -execdir git status \;
  • find . -type d -name .git recursively find all .git repositories
  • -print print the path of the .git directory
  • -execdir git status \; run git status in that diectory (the directory containing the git directory)

Solution 7:[7]

You can use "git ls-files --modified --deleted --exclude-standard" to list all modified and deleted files (--exclude-standard is not probably needed there, but just in case you want to list all unknown files that are not ignored with --other...). You can then check if the output of this command is empty.

Or you can check the exit status of "git diff --quiet HEAD" if you want to check if "git commit -a" would pick up anything, or "git diff --cached --quiet HEAD" if you want to check if "git commit" would pick anything (or one of its plumbing relatives: git-diff-files or git-diff-index).

Solution 8:[8]

for rp in /srv/*/
do
  printf '\ec'
  cd "$rp"
  git status
  echo "${rp%/}"
  read
done

Example

Solution 9:[9]

It's not very fancy for formatting but how about something like

find . -iname ".git" -type d | sed -rne "s|(.+)/\.git|echo \1;cd \1;git status;cd /data|p" | bash

Solution 10:[10]

I realise this is a pretty old thread now but in Windows 10 I couldn't get the WHILE/DO loop from @Tasos solution to work so I converted it to PowerShell.

This version also prints out the status of each uncommitted change as well as a bit of formatting for readability to group by folder names.

cd C:\Projects

$msgs = @()
gci ".git" -Directory -Recurse -Hidden | % {
    $dir = $_
    cd $dir\..

    $gitMsgs = (git status -s)
    if ( $gitMsgs ) {
        $msgs += "$dir ****************************"
        $msgs += $gitMsgs
        $msgs += ""
    } 
}
$msgs | % { Write-Host $_ }

Solution 11:[11]

cargo install fd-find https://github.com/sharkdp/fd#installation

find_nonclean_git () {
    fd -E Trash -H '^\.git$' ~ -x echo '{//}' | while read dir; do
        cd $dir
        echo $dir >/dev/null
        #git status -s | grep -c ^
        lnnum=$(git status -s | grep -c ^)
        #if [[ "$lnnum" != "0" ]]; then
        if (( $lnnum > 0 )); then
            echo $dir $lnnum
        fi
    done
}