Home Notes Quotes

Auto Pusher 🖥️➕🚀

June 29, 2025 • 6 min read • by Katzir

The Origin Story

One evening, after realizing my GitHub streak had dropped once again, I decided enough was enough. I needed a tool to handle those daily “keeping-alive” commits automatically—no babysitting, no extra dependencies. Thus, Auto Pusher was born: a small suite of scripts that fetch a free ZenQuotes API quote, append it to quotes.txt, and push to GitHub, all scheduled on Windows via PowerShell.

Project Layout

Here’s how I organized the repo:

README.md — Your First Stop

The README is your doorway. It explains:

Whenever you need a refresher, this is the file to open:


https://github.com/ItakatzI/auto-pusher/blob/main/README.md
      

.env.example — Secret Sauce

To avoid hard-coding credentials and file names, I use an environment file. Copy it to .env and fill in your values:


# .env.example
REPO_DIR=/c/path/to/your/repo-to-commit
REPO_ALT=/c/path/to/your/another-repo-to-commit
REPO_DIR2=C:\Users\path\to\auto-push\folder\quotesForGit
TARGET_FILE=quotes.txt
      

This file is ignored by Git, so your personal tokens or emails never leak.

auto_commit.sh — The Heart in Bash

Although this project lives on Windows, I wrote the core in Bash to keep it lightweight and dependency-free. It's meant to be used on two repositories, alternating between them to contribute to two GitHub repos:


#!/usr/bin/env bash

# === Config ===
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_PATH="$SCRIPT_DIR/.env"
LOG_PATH="$SCRIPT_DIR/push_log.txt"
LAST_REPO_FILE="$SCRIPT_DIR/.last_repo"

exec > >(tee -a "$LOG_PATH") 2>&1
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting auto_commit.sh"

# Load .env
if [ -f "$ENV_PATH" ]; then
  export $(grep -v '^#' "$ENV_PATH" | xargs)
else
  echo "[✘] .env file not found at $ENV_PATH"
  exit 1
fi

# Validate
if [ -z "$REPO_DIR" ] || [ -z "$REPO_ALT" ] || [ -z "$TARGET_FILE" ]; then
  echo "[✘] Missing REPO_DIR, REPO_ALT or TARGET_FILE in .env"
  exit 1
fi

# Choose repo
if [ -f "$LAST_REPO_FILE" ]; then
  LAST=$(<"$LAST_REPO_FILE")
else
  LAST="ALT"
fi

if [ "$LAST" = "ALT" ]; then
  REPO="$REPO_DIR"
  echo "DIR" >"$LAST_REPO_FILE"
else
  REPO="$REPO_ALT"
  echo "ALT" >"$LAST_REPO_FILE"
fi

echo "[✔] Using repo: $REPO"
cd "$REPO" || { echo "[✘] Failed to cd into $REPO"; exit 1; }
git pull

MIN_COMMITS=${MIN_COMMITS:-1}
MAX_COMMITS=2
NUM_COMMITS=$((RANDOM % (MAX_COMMITS - MIN_COMMITS + 1) + MIN_COMMITS))
echo "[✔] Planning $NUM_COMMITS motivational commits..."

for ((i=0; i> "$TARGET_FILE"
  git add "$TARGET_FILE"
  git commit -m "Motivation: \"$LINE\""
  git checkout main
  git merge daily-quote
  git branch -d daily-quote
  git push
done

echo "[✔] Completed $NUM_COMMITS commits."
git push origin HEAD:main
      

setup.ps1 — One-Click Setup

Rather than manually running the script, I automated it and registered the daily scheduler task:


# setup.ps1

function Load-EnvFile {
  $envPath = Join-Path $PSScriptRoot ".env"
  if (Test-Path $envPath) {
    Get-Content $envPath | ForEach-Object {
      if ($_ -match '^\s*([^#][^=]*)\s*=\s*(.*)\s*$') {
        [Environment]::SetEnvironmentVariable($matches[1], $matches[2])
      }
    }
  } else {
    Write-Error "[✘] .env file not found"
    exit 1
  }
}

Load-EnvFile
$proj = $env:REPO_DIR2
$sched = Join-Path $proj "schedule_tasks.ps1"
$bash  = Join-Path $proj "auto_commit.sh"

powershell.exe -ExecutionPolicy Bypass -File "`"$sched`""

$trig   = New-ScheduledTaskTrigger -Daily -At 11:00am
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
          -Argument "-File `"$sched`""
Register-ScheduledTask -Action $action -Trigger $trig `
                      -TaskName "AutoPusherScheduler" -Force
      

schedule_tasks.ps1 — Wake Up and Go

This script cleans up old tasks and schedules a few random pushes each day:


# schedule_tasks.ps1

Add-Content -Path "$env:TEMP\push_scheduler_log.txt" `
  -Value "[$(Get-Date)] scheduling run"

Get-Content "$PSScriptRoot\.env" | ForEach-Object {
  if ($_ -match '^(.*?)=(.*)$') {
    [Environment]::SetEnvironmentVariable($matches[1], $matches[2])
  }
}

$repoDir  = $env:REPO_DIR2
$bashPath = "C:\Program Files\Git\bin\bash.exe"

Get-ScheduledTask -TaskName "AutoPusher_*" |
  Unregister-ScheduledTask -Confirm:$false

$num = Get-Random -Minimum 1 -Maximum 4
for ($i=0; $i -lt $num; $i++) {
  $h = Get-Random -Minimum 20 -Maximum 22
  $m = Get-Random -Minimum 0  -Maximum 59
  $t = "{0:00}:{1:00}" -f $h,$m
  $arg = "-c `"cd '$repoDir' && bash ./auto_commit.sh`""
  New-ScheduledTaskAction -Execute $bashPath -Argument $arg |
    Register-ScheduledTask -Trigger (New-ScheduledTaskTrigger -Daily -At $t) `
      -TaskName "AutoPusher_$i" -Force
}
      

quotes.txt — Your Quotes Log

This plain text file accumulates inspirational quotes over time, building your personal archive.

Lessons Learned & Pitfalls

Get the Code

Dive in and try it yourself: github.com/ItakatzI/auto-pusher

← Back to all posts

Let's Conjure Something Epic

I'm always on the lookout for new quests—collaborate, chat, or challenge me to build the next VR dragon simulator!