Refreshing multiple git repos
File under “blogging so I remember how I did this”…
I often have the situation where I have a directory full of related git repositories related to one area of work.  So I have for example ~/work/team-a/platitude-generator and ~/work/team-a/memes and so on.
And I just want everything up to date - especially if I come back after my non-working day or a holiday.
I used to use a tool called gws to manage this, but it has a few bugs and quirks - it caches too much and I had to manually edit config files and delete caches too often.
And I did some digging and stack-overflow-browsing - I ended up just using a quite simple script.  It doesn’t cache anything, it’s slow as it runs git fetch for every repo every time, but honestly that’s usually what I want anyway.
A few notes after the script.
#!/bin/bash -e
RED='\033[0;31m'
GREEN='\033[0;33m'
NC='\033[0m'
for dir in */; do
    cd "$dir" || continue
    if [ -d ".git" ]; then
        current_branch=$(git branch --show-current || "no branch")
        echo "processing $dir on $current_branch"
        status=$(git status -s | { grep -v "^?? " || true; } )
        if [ -n "$status" ]; then
            echo -e "${RED}$dir has uncommitted changes --skipping${NC}"
        else
            git fetch -q
            incoming_changes=$(git rev-list --count "..@{u}")
            echo -e "Pulling ${GREEN}$incoming_changes${NC} changes"
            git --no-pager log --pretty=format:"%h%x09%an%x09%ad%x09%s" --date=short "..@{u}"
            git pull --ff-only || rc="$?"
            if [ -n "$rc" ]; then
              echo -e "${RED}$dir fast forward failed: ${rc} ${NC}";
            fi
        fi
    else
        echo "$dir is not a git repository"
    fi
    cd ..
done
Notable bits:
status=$(git status -s | { grep -v "^?? " || true; } )- this ignores added files. I often have junk in repos - I don’t want my update to fail because I have a log file or something kicking around!git pullwill fail anyway if the file is in conflict.- I don’t check against 
main- if I’m on a branch I usually want to update that branch, because that’s where I’m working. (maybe I should add a warning ifmainhas un-merged changes?) ..@{u}is a new-ish feature forgit logandgit rev-listwhich looks at differences between the current branch and its upstream branch. Very handygit pull --ff-onlywill fail quite often, but that’s OK - I want to be prompted to manually intervene if I’ve made local changes.- I use 
|| trueand similar because I’m running#!/bin/bash -eat the top, and any error will abort the script. I find it much easier to default to failing and manually handle errors than to default to ignoring errors. - Shellcheck is my friend - I have it as a VSCode plugin and it catches most things.
 
I hope this is helpful to others (and to future-me).