Skip to content

Instantly share code, notes, and snippets.

@mzabriskie
Last active August 29, 2024 14:03
Show Gist options
  • Save mzabriskie/6631607 to your computer and use it in GitHub Desktop.
Save mzabriskie/6631607 to your computer and use it in GitHub Desktop.
Check git status of multiple repos

If you're like me you have a dir like ~/Workspace/Github where all your git repos live. I often find myself making a change in a repo, getting side tracked and ending up in another repo, or off doing something else all together. After a while I end up with several repos with modifications. This script helps me pick up where I left off by checking the status of all my repos, instead of having to check each one individually.

Usage:

git-status [directory]

This will run git status on each repo under the directory specified. If called with no directory provided it will default to the current directory.

#!/bin/bash
dir="$1"
# No directory has been provided, use current
if [ -z "$dir" ]
then
dir="`pwd`"
fi
# Make sure directory ends with "/"
if [[ $dir != */ ]]
then
dir="$dir/*"
else
dir="$dir*"
fi
# Loop all sub-directories
for f in $dir
do
# Only interested in directories
[ -d "${f}" ] || continue
echo -en "\033[0;35m"
echo "${f}"
echo -en "\033[0m"
# Check if directory is a git repository
if [ -d "$f/.git" ]
then
mod=0
cd $f
# Check for modified files
if [ $(git status | grep modified -c) -ne 0 ]
then
mod=1
echo -en "\033[0;31m"
echo "Modified files"
echo -en "\033[0m"
fi
# Check for untracked files
if [ $(git status | grep Untracked -c) -ne 0 ]
then
mod=1
echo -en "\033[0;31m"
echo "Untracked files"
echo -en "\033[0m"
fi
# Check for unpushed changes
if [ $(git status | grep 'Your branch is ahead' -c) -ne 0 ]
then
mod=1
echo -en "\033[0;31m"
echo "Unpushed commit"
echo -en "\033[0m"
fi
# Check if everything is peachy keen
if [ $mod -eq 0 ]
then
echo "Nothing to commit"
fi
cd ../
else
echo "Not a git repository"
fi
echo
done
@ocarlsen
Copy link

ocarlsen commented May 21, 2019

for x in $(find . -type d -name ".git"); do cd $(dirname $x); pwd; git status; done

This checks the first repo, then remains there and looks for other repos there, so it gives a bunch of "no such file..."

Yeah it doesn't cd back out of the directory after going into it. If you're using Bash, this works:

for x in $(find . -type d -name ".git"); do pushd $(dirname $x); pwd; git status; popd; done

@danispringer
Copy link

danispringer commented May 21, 2019

for x in $(find . -type d -name ".git"); do cd $(dirname $x); pwd; git status; done

This checks the first repo, then remains there and looks for other repos there, so it gives a bunch of "no such file..."

Yeah it doesn't cd back out of the directory after going into it. If you're using Bash, this works:

for x in $(find . -type d -name ".git"); do pushd $(dirname $x); pwd; git status; popd; done

Hey @ocarlsen
one-liners have their beauty, but it looks hard to customize (for example, I set it to not print anything if the response is nothing to commit, working tree clean)

But that's great to have, too!

I currently use https://github.com/DaniSpringer/multi-git-status

Thanks,
Dani

@contexua
Copy link

contexua commented Oct 9, 2019

thanks, works wonderful - very simple - just checks one directory level. Anything else is a different script I think 'keep it simple'

@danspringer - use an editor to place this script in /usr/bin on linux, then chmod +x to allow it toe be execcutable

@burningTyger
Copy link

@danispringer I started using yours too. Is there a solution that would let me add specific repos to a list and only check those? My dev dir is somewhat cluttered and I'd rather selectively check the ones I'm interested in. Otherwise thank you.

@thorgeir93
Copy link

for x in $(find . -type d -name ".git"); do cd $(dirname $x); pwd; git status; done

This checks the first repo, then remains there and looks for other repos there, so it gives a bunch of "no such file..."

Yeah it doesn't cd back out of the directory after going into it. If you're using Bash, this works:

for x in $(find . -type d -name ".git"); do pushd $(dirname $x); pwd; git status; popd; done

Simplified output version:

for x in $(find . -type d -name ".git"); do pushd $(dirname $x) > /dev/null; (set -x; git status -s $PWD); popd > /dev/null; done

Example usage:

[thorgeir@MEGAS thorgeir]$ for x in $(find . -type d -name ".git"); do pushd $(dirname $x) > /dev/null; (set -x; git status -s $PWD); popd > /dev/null; done
+ git status -s /home/thorgeir/github/thorgeir/linux_configs
 M st_terminal_config.h
+ git status -s /home/thorgeir/github/thorgeir/utils
+ git status -s /home/thorgeir/github/thorgeir/calendar_icelandic
?? cal_is/test_cal_is.py

@fraber
Copy link

fraber commented Dec 3, 2020

Great starting point!
However, I've got >200 repos, so I only want to show the modified stuff. Please see the code below.

#!/bin/bash                                                                                                                                                     

dir="$1"
pushd .

# No directory has been provided, use current                                                                                                                   
if [ -z "$dir" ]
then
    dir="`pwd`"
fi

# Make sure directory ends with "/"                                                                                                                             
if [[ $dir != */ ]]
then
    dir="$dir/*"
else
    dir="$dir*"
fi

# Loop all sub-directories                                                                                                                                      
for f in $dir
do
    # Only interested in directories                                                                                                                            
    [ -d "${f}" ] || continue

    # Check if directory is a git repository                                                                                                                    
    if [ -d "$f/.git" ]
    then
    cd $f
    if [ $(git status --porcelain | wc -l) -eq 0 ]
    then
        continue
    fi
    echo -en "\033[0;35m"
    echo "${f}"
    echo -en "\033[0m"
    git status --porcelain
    fi
done
popd

@danispringer
Copy link

@danispringer I started using yours too. Is there a solution that would let me add specific repos to a list and only check those? My dev dir is somewhat cluttered and I'd rather selectively check the ones I'm interested in. Otherwise thank you.

Still need?

@Pablo1107
Copy link

When using git worktree the .git on the branches directory is actually a file that redirects to the main repo, so I change this to check if .git exists whenever is a directory or a file.

        # Check if directory is a git repository
	if [ -e "$f/.git" ]
	then
		[...]
	else
		echo "Not a git repository"
	fi

@shopglobal
Copy link

shopglobal commented Aug 21, 2021

Great script thanks for sharing!
I decided to alter the "if" statement which checks/fixes path to an elif statement to stop a local error on Ubuntu.

The script runs fine, but without this alteration it showed a small console error about syntax on line 12 regarding double brackets. I am not a shell expert, but I like using scripts when possible to save time. This modification works without error. Saves me time updating large projects. My version of the script has some added logic exclusive for my projects, thanks again.

Here's my mod: https://gist.github.com/shopglobal/0b7a46613f2335f150de855e717396ca/revisions

Original (if):

# No directory has been provided, use current
if [ -z "$dir" ]
then
    dir="`pwd`"
fi

# Make sure directory ends with "/"
if [[ $dir != */ ]]
then
	dir="$dir/*"
else
	dir="$dir*"
fi

Modified (elif):

# No directory has been provided, use current
if [ -z "$dir" ]
then
    dir="`pwd`"

# Make sure directory ends with "/"
elif [ $dir != */ ]
then
	dir="$dir/*"
else
	dir="$dir*"
fi

@marouenes
Copy link

Maybe considering adding a help context would be nice :D. I can submit an improvement if it's fine.

@melMass
Copy link

melMass commented May 16, 2022

Thanks, for recursion you can replace line 70 with ./$0 "${f}"

@jadjay
Copy link

jadjay commented Oct 27, 2022

Hello,

I add a "DEBUG" var to get shorter results on large directories

@jadjay
Copy link

jadjay commented Oct 27, 2022

the patch

2a3
> DEBUG=no #yes
24,27c25,30
<
<       echo -en "\033[0;35m"
<       echo "${f}"
<       echo -en "\033[0m"
---
>       if [[ $DEBUG == "yes" ]]
>       then
>               echo -en "\033[0;35m"
>               echo "${f}"
>               echo -en "\033[0m"
>       fi
31a35,41
>               if [[ $DEBUG != "yes" ]]
>               then
>                       echo -en "\033[0;35m"
>                       echo "${f}"
>                       echo -en "\033[0m"
>               fi
>
65c75,78
<                       echo "Nothing to commit"
---
>                       if [[ $DEBUG == "yes" ]]
>                       then
>                               echo "Nothing to commit"
>                       fi
70c83,90
<               echo "Not a git repository"
---
>               if [[ $DEBUG == "yes" ]]
>               then
>                       echo "Not a git repository"
>               fi
>       fi
>       if [[ $DEBUG == "yes" ]]
>       then
>               echo
72,73d91
<
<       echo
74a93
>

@Patil-1008
Copy link

can anyone please help me how to use this snippet in my unix? do I need to save this file and make it executable?

@Pablo1107
Copy link

can anyone please help me how to use this snippet in my unix? do I need to save this file and make it executable?

Yes, you need to download the script and run chmod +x git-status.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment