List All Git Repositories with Modified Files

Publish date: Nov 19, 2020
Tags: git, cli, linux, bash, scripting

Motivation

As I’m using more than one machine to do my work, I often forget to upload updates to a git repository. It causes me to deal with unnecessary merges or even requiring me to go back to previous computer to push the changes prior to start my work.

The Solution

Keep track of all repositories that have uncommitted changes. In my case, it is sufficient because I use to push changes immediately after committing.

Low Tech

To handle this I used a simpler approach: a bash scripts that finds all repositories and filter only the ones with uncommitted changes. I’m using find, sed, git ls-files and a simple for-loop in the bash script.

Implementation and comments

modified-repos.sh

#!/usr/bin/env bash

if [ -n "$1" ]; then DIR="$1"; else DIR="$HOME"; fi
if [ "$1" == "help" ];
then
    echo 'Usage:   $ ./modified-repos.sh [directory-name]'
    echo '         directory-name: optional parameters, defaults to $HOME'
    echo 'Example: $ ./modified-repos.sh .'
    exit 0;
fi

for f in $(find $DIR -name .git -type d -not -name 'node_modules' 2> /dev/null | sed 's/\/.git$/'/)
do
    if [ $(git -C $f ls-files -m | wc -l) -ne 0 ]; then echo "$f"; fi
done

Handle args

Accepts: a base directory or “help” Defaults to $HOME as base directory

find command

The find searches for .git directories and uses the -not -name to exclude the node_modules folder. It also ignores errors caused by directories in which the current user does not have permission.

sed command

Remove the .git part of the directory to keep the repository root directory only.

git ls-files

The line if [ $(git -C $f ls-files -m | wc -l) -ne 0 ]; then echo "$f"; fi is the more interesting one. Let’s break down it:

git -C <directory-name>: allows me to run a git command from another directory ls-files -m: command to list modified git controlled files wc -l: count the number modified files given by ls-files -m

If the number of modified files is not zero, it outputs the directory name. Otherwise does nothing.

The expected output

$ ./modified-repos.sh .

May output:

./elisp/emacs-bitbucket
./elisp/mosql
./elisp/company-sql
./elisp/mopomo