Skip to content

Instantly share code, notes, and snippets.

@e0da
Created March 15, 2026 23:36
Show Gist options
  • Select an option

  • Save e0da/971b6cb85008dd8a19861c4f83be5f21 to your computer and use it in GitHub Desktop.

Select an option

Save e0da/971b6cb85008dd8a19861c4f83be5f21 to your computer and use it in GitHub Desktop.
Gource wrapper for visualizing multiple repositories
#!/bin/bash -e
# Gource wrapper for visualizing multiple repositories
# Based on: https://github.com/acaudwell/Gource/wiki/Visualizing-Multiple-Repositories
if [ -n "$DEBUG" ]; then
set -x
echo '$*:' "$*"
echo '$@:' "$@"
echo '$#:' "$#"
echo '$?:' "$?"
fi
usage="
gources: Visualize multiple git repositories with Gource
Usage:
gources [options] <repo1> [repo2] [repo3] ...
Arguments:
repo1, repo2, ... Git repository names/directories to visualize
Options:
-h, --help Show this help message and exit
-o, --output FILE Output combined log to FILE instead of running gource
--no-separate Don't separate repositories into different directory trees
--gource-opts OPTS Pass additional options to gource (quote them)
Examples:
gources myproject otherproject
gources --no-separate frontend backend api
gources -o combined.log repo1 repo2 repo3
gources --gource-opts '--hide-root --seconds-per-day 0.1' app lib
"
# Parse arguments
output_file=""
separate_repos=true
gource_opts=""
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
echo "$usage"
exit 0
;;
-o|--output)
output_file="$2"
shift 2
;;
--no-separate)
separate_repos=false
shift
;;
--gource-opts)
gource_opts="$2"
shift 2
;;
-*)
echo "Unknown option: $1" >&2
echo "$usage" >&2
exit 1
;;
*)
# Repository arguments
break
;;
esac
done
# Check if we have repositories to process
if [ $# -eq 0 ]; then
echo "Error: No repositories specified" >&2
echo "$usage" >&2
exit 1
fi
# Check if gource is available
if ! command -v gource >/dev/null 2>&1; then
echo "Error: gource is not installed. Please install it first." >&2
echo "On macOS: brew install gource" >&2
echo "On Ubuntu/Debian: apt-get install gource" >&2
exit 1
fi
# Create temporary directory for log files
temp_dir=$(mktemp -d)
trap "rm -rf '$temp_dir'" EXIT
combined_log="$temp_dir/combined.txt"
# Process each repository
for repo in "$@"; do
if [ ! -d "$repo" ]; then
echo "Warning: Repository '$repo' does not exist, skipping" >&2
continue
fi
if [ ! -d "$repo/.git" ]; then
echo "Warning: '$repo' is not a git repository, skipping" >&2
continue
fi
echo "Processing repository: $repo" >&2
# Generate custom log for this repository
# Use a sanitized name for the log file to avoid issues with special characters
repo_name=$(basename "$repo" | sed 's/[^a-zA-Z0-9._-]/_/g')
[ "$repo_name" = "." ] && repo_name="current_directory"
repo_log="$temp_dir/${repo_name}.txt"
gource --output-custom-log "$repo_log" "$repo"
# Add repository name as parent directory if separating repos
if [ "$separate_repos" = true ]; then
if command -v gsed >/dev/null 2>&1; then
# Use GNU sed if available (Linux)
gsed -i -r "s#(.+)\|#\1|/$repo#" "$repo_log"
else
# Use macOS sed (BSD sed)
sed -i '' -E "s#(.+)\|#\\1|/$repo#" "$repo_log"
fi
fi
done
# Combine all logs and sort by timestamp
cat "$temp_dir"/*.txt 2>/dev/null | sort -n > "$combined_log"
# Check if we got any data
if [ ! -s "$combined_log" ]; then
echo "Error: No valid git repositories found or no commits to visualize" >&2
exit 1
fi
# Either output to file or run gource
if [ -n "$output_file" ]; then
cp "$combined_log" "$output_file"
echo "Combined log saved to: $output_file" >&2
else
echo "Starting Gource visualization..." >&2
# shellcheck disable=SC2086
exec gource $gource_opts "$combined_log"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment