#!/bin/bash # debug script set -x # These are the only lines that should require updating frequency_mins=2 # These values are automatically determined based on the scipt path sync_script=$(readlink -f "${BASH_SOURCE[0]}") script_dir=$(dirname "$sync_script") cronjob="*/${frequency_mins} * * * * ${sync_script}" script_name=$(basename "$sync_script") # Get current crontab content, suppress error if crontab is empty current_crontab=$(crontab -l 2>/dev/null) # Check if the exact cron job already exists using fixed string (-F) and whole line (-x) match if echo "$current_crontab" | grep -Fxq "$cronjob"; then echo "${script_name} cron job is already correctly configured." else echo "${script_name} cron job needs update or addition." # Use command grouping to construct the new crontab content: # 1. List current crontab (or nothing if empty), suppressing errors. # 2. Filter out any existing lines related to this specific script. # 3. Echo the desired cron job line. { crontab -l 2>/dev/null | grep -v "$sync_script"; echo "$cronjob"; } | crontab - update_result=$? if [[ $update_result -eq 0 ]]; then echo "cron job updated/added successfully." else echo "Warning: Failed to update crontab." >&2 fi fi # navigate to the repo cd "${script_dir}" || (echo 'unable to find repo' && exit 1) # if this is macos, make sure '/usr/local/git/git-google/bin' is in $PATH if [[ "$OSTYPE" == "darwin"* ]]; then if ! echo "$PATH" | grep -q "/usr/local/git/git-google/bin"; then export PATH="/usr/local/git/git-google/bin:$PATH" fi fi # Stage ALL changes, including new files and modifications git add . # Check if there are any *meaningful* staged changes (respecting diff filters) # git diff --staged --quiet exits with 0 if NO differences, 1 if differences exist. # The '!' negates the exit status, so the 'if' block runs if there ARE differences. if ! git diff --staged --quiet; then # Only commit if there are staged changes visible after filtering echo "Staged changes detected, creating commit..." # Use -m because we already staged everything with 'git add .' git commit -m "${script_name} ($(hostname -s)) $(date +"%Y-%m-%dT%H:%M:%SZ")" else echo "No relevant changes detected to commit (changes might be filtered)." # Optional but recommended: Reset the index if the only staged changes were filtered out. # This prevents the file from showing as "changes staged for commit" on a later 'git status' # if only the filtered line was changed and staged by 'git add .'. git reset HEAD --quiet fi # make sure we are authenticated with git origin if ! git remote update origin --prune; then echo 'unable to authenticate to remote' exit 1 fi local_commit=$(git rev-parse HEAD) remote_commit=$(git rev-parse origin/main) if [[ "$local_commit" != "$remote_commit" ]]; then # sleep for a random time between 1-45 seconds to avoid collisions sleepy_time=$(( ( RANDOM % 45 ) + 1 )) echo "sleeping for $sleepy_time seconds..." sleep $sleepy_time else echo 'no pending changes to sync, exiting...' exit 0 fi # which is newer, our code or the origin? local_commit=$(git rev-parse HEAD) remote_commit=$(git rev-parse origin/main) if [[ "$local_commit" == "$remote_commit" ]]; then echo "local and remote are in sync" elif git merge-base --is-ancestor "$local_commit" "$remote_commit"; then echo "remote is ahead of local" git pull --rebase origin main elif git merge-base --is-ancestor "$remote_commit" "$local_commit"; then echo "local is ahead of remote" git push origin main else echo "local and remote have diverged" # if remote is newer, use a 'theirs' strategy if [[ $(git log --pretty=format:"%at" -n 1 origin/main) -gt $(git log --pretty=format:"%at" -n 1 HEAD) ]]; then echo "remote is newer" git pull --rebase -X theirs origin main else echo "local is newer" git pull --rebase -X ours origin main fi git push origin main fi