Git and libgit2

Updating Trees of Git Repositories

Published 2023-03-11. Last modified 2025-10-03.
Time to read: 2 minutes.

This page is part of the git collection.

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

/etc/environment is a system-wide configuration file, which is sourced every time a user logs in. It is owned by root, so your account needs to be a member of the admin group, or you will have to use sudo to modify it.

The /etc/environment file in all of my systems defines two environment variables:

sites
Points to the root of the website directory tree
work
Points to the root of the code project tree
/etc/environment
export sites=/var/www
export work=/var/work

Now $sites and $work will be defined for all users every time they log in.

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
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

I first wrote a Bash version of a command I called update, years later I wrote a multithreaded Ruby version that runs orders of magnitude faster for large directory trees. I called this version git-update; note that it requires a properly set up Ruby development environment.

The site and work environment variables are used by the update scripts.

#!/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 || exit 2
  echo -e "\n${HIGHLIGHT}Updating `pwd`$NORMAL"
  git pull
  cd - > /dev/null || exit 3
done

The Ruby version of update is waaaay faster than the Bash version! Install the git-tree gem and get several git-related commands, including git-update. 💕💕💕

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

Shell
$ git 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 specify the roots of one or more directory trees of git repositories:

Shell
$ git update /path/to/another/tree $my_gems $my_plugins
Updating /path/to/another/tree /mnt/f/work/ruby/my_gems /mnt/f/work/jekyll/my_plugins 
😁

I hope you find the update scripts to be as useful as I have!

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.