Git and libgit2
Mike Slinn

Updating Trees of Git Repositories

Published 2023-03-11.
Time to read: 1 minutes.

This page is part of the git collection, categorized under Git.

I need to keep several hundred git repositories up-to-date. I have a directory tree of website repos, and a directory tree of code repos. Updating these trees was tedious until I wrote the initial version of the update script back in 2008.

Environment Variables

My ~/.bashrc script defines two environment variables, each of which point at the root of one of the following directory trees:

sites
Points to the root of the website directory tree
work
Points to the root of the code project tree
~/.bashrc
export sites=/var/www
export work=/var/work

In addition, I define subordinate environment variables for each project in a file called $work/.evars

$work/.evars
export cadenzaHome=$work/cadenzaHome
export cadenzaCode=$cadenzaHome/cadenzaCode
export cadenzaDependencies=$cadenzaCode/cadenzaDependencies
export awslib_scala=$cadenzaDependencies/awslib_scala
export shoppingcart=$cadenzaDependencies/shoppingcart
export clients=$work/clients
export django=$work/django
export msp=$sites/www.mslinn.com
... 

$work/.evars is included by ~/.bashrc

~/.bashrc
export sites=/var/www
export work=/var/work
source $work/.evars

Switching Directories

The above environment variables allow me to easily move to a git project directory without having to remember where it resides on the computer that I am currently using:

Shell
$ cd $clients

$ pwd
/var/work/clients 

Updating Git Directory Trees

The site and work environment variables are used by the update script:

#!/bin/bash

# Update all git directories below current directory or specified directory
# Skips directories that contain a file called .ignore
# See https://stackoverflow.com/a/61207488/553865

if [ "$( curl -sL -w "%{http_code}\n" https://www.github.com -o /dev/null )" != 200 ]; then
  echo "Cannot connect to GitHub"
  exit 2
fi

HIGHLIGHT="\e[01;34m"
NORMAL='\e[00m'

export PATH=${PATH/':./:'/:}
export PATH=${PATH/':./bin:'/:}
#echo "$PATH"

if [ -z "$1" ]; then
  ROOTS="$sites $work"
else
  ROOTS="$@"
fi

echo "Updating $ROOTS"
DIRS="$( find -L $ROOTS -type d \( -execdir test -e {}/.ignore \; -prune \) -o \( -execdir test -d {}/.git \; -prune -print \) )"

echo -e "${HIGHLIGHT}Scanning ${PWD}${NORMAL}"
for d in $DIRS; do
  cd "$d" > /dev/null
  echo -e "\n${HIGHLIGHT}Updating `pwd`$NORMAL"
  git pull
  cd - > /dev/null
done

Most of the time I want to update everything in both directory trees, so for that no arguments are required:

Shell
$ update
Updating /var/www /var/work
Updating /var/work/cadenzaHome/cadenzaCode/cadenzaDependencies/awslib_scala
Already up to date.
Updating /var/work/cadenzaHome/cadenzaCode/cadenzaDependencies/shoppingcart Already up to date.
...

It is also possible to update an arbitrary directory tree of git repositories:

Shell
$ update /path/to/another/tree
Updating /path/to/another/tree 
😁

I hope you find the update script as useful as I have!