Pull/update all repos in a path: git update.sh

From wikieduonline
Jump to navigation Jump to search
#!/bin/bash

# 1. Secure temporary file handling
JOBLOG=$(mktemp)
trap '[ -n "${FAILURES:-}" ] || rm -f "$JOBLOG"' EXIT

# Prevent terminal-based password prompts from freezing background parallel tasks
export GIT_TERMINAL_PROMPT=0

# 2. Define and export the update task
sync_repo() {
    # Fast, zero-fork path cleaning using Bash parameter expansion
    local repo="${1%/.git}"

    # ANSI Colors for terminal output
    local CYAN='\033[1;36m'
    local GREEN='\033[1;32m'
    local RED='\033[1;31m'
    local NC='\033[0m' # No Color

    # Uses your default system HTTPS/Credential helper settings natively
    local fetch_out
    fetch_out=$(git -C "$repo" fetch --all 2>&1)
    if [ $? -ne 0 ]; then
        printf "${CYAN}%s${NC} ${RED}FETCH FAILED${NC}\n" "$repo"
        echo "$fetch_out" >&2
        return 1
    fi

    local pull_out
    local status
    pull_out=$(git -C "$repo" pull --ff-only --recurse-submodules 2>&1)
    status=$?
    
    # Extract the last non-empty line of output safely
    local summary
    summary=$(awk 'NF {last=$0} END {print last}' <<< "$pull_out")

    # Clean single-line formatting separated by a single space
    if [ $status -eq 0 ]; then
        printf "${CYAN}%s${NC} ${GREEN}%s${NC}\n" "$repo" "$summary"
    else
        printf "${CYAN}%s${NC} ${RED}%s${NC}\n" "$repo" "$summary"
        echo "$pull_out" >&2
        return 1
    fi
}
export -f sync_repo

# 3. Find and update repos in parallel (Single line, no backslashes)
find . -name ".git" -type d -prune -print0 | parallel -0 -j 8 --group --joblog "$JOBLOG" sync_repo

# 4. Parse failures and exit with the correct status code
FAILURES=$(awk -F'\t' 'NR>1 && $7!=0 {sub(/^sync_repo /, "", $9); sub(/\/\.git$/, "", $9); print $9}' "$JOBLOG")

echo ""
if [ -n "$FAILURES" ]; then
    printf "\033[1;31mFailures occurred in the following repositories:\033[0m\n"
    printf "%s\n" "$FAILURES"

    printf "\n\033[1;33mDebug log preserved at:\033[0m %s\n" "$JOBLOG"
    exit 1
else
    printf "\033[1;32mAll repositories synced successfully!\033[0m\n"
    exit 0
fi

Basic One liner[edit]

Pull all repos in a path, including subdirectories:

  • find . -name ".git" -type d | sed 's/\/.git//' | parallel 'echo -e "\n=== {} ===" && git -C {} pull 2>&1'

Related[edit]

See also[edit]

Advertising: