Skip to content

Cleanup gh-pages History #6

Cleanup gh-pages History

Cleanup gh-pages History #6

name: Cleanup gh-pages History
on:
schedule:
# Run on the 1st of every month at 3:00 AM UTC
- cron: '0 3 1 * *'
workflow_dispatch:
inputs:
keep_days:
description: 'Keep commits from last N days (default: 30)'
required: false
type: number
default: 30
dry_run:
description: 'Dry run (show what would be done without pushing)'
required: false
type: boolean
default: false
permissions:
contents: write
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Checkout gh-pages
uses: actions/checkout@v4
with:
ref: gh-pages
fetch-depth: 0 # Full history needed for squashing
- name: Cleanup old history
shell: bash
run: |
set -e
KEEP_DAYS="${{ github.event.inputs.keep_days || 30 }}"
DRY_RUN="${{ github.event.inputs.dry_run || 'false' }}"
echo "=== gh-pages History Cleanup ==="
echo "Keep commits from last: ${KEEP_DAYS} days"
echo "Dry run: ${DRY_RUN}"
echo ""
# Get current branch info
CURRENT_COMMITS=$(git rev-list --count HEAD)
CURRENT_SIZE=$(du -sh .git | cut -f1)
echo "Current state:"
echo " Commits: ${CURRENT_COMMITS}"
echo " .git size: ${CURRENT_SIZE}"
echo ""
# Find the cutoff date
CUTOFF_DATE=$(date -d "-${KEEP_DAYS} days" +%Y-%m-%d 2>/dev/null || date -v-${KEEP_DAYS}d +%Y-%m-%d)
echo "Cutoff date: ${CUTOFF_DATE}"
# Find commits to keep (after cutoff date)
COMMITS_TO_KEEP=$(git rev-list --after="${CUTOFF_DATE}" HEAD | wc -l | tr -d ' ')
echo "Commits after cutoff: ${COMMITS_TO_KEEP}"
if [ "${COMMITS_TO_KEEP}" -eq 0 ]; then
echo "No recent commits found, keeping at least the latest commit"
COMMITS_TO_KEEP=1
fi
# If we have very few commits, nothing to clean
if [ "${CURRENT_COMMITS}" -le "${COMMITS_TO_KEEP}" ]; then
echo ""
echo "Nothing to clean up - all commits are within retention period"
exit 0
fi
COMMITS_TO_SQUASH=$((CURRENT_COMMITS - COMMITS_TO_KEEP))
echo "Commits to squash: ${COMMITS_TO_SQUASH}"
echo ""
# Show what will be removed
echo "=== Commits to be squashed ==="
git log --oneline --skip=${COMMITS_TO_KEEP} -20 || true
if [ "${COMMITS_TO_SQUASH}" -gt 20 ]; then
echo "... and $((COMMITS_TO_SQUASH - 20)) more"
fi
echo ""
if [ "${DRY_RUN}" = "true" ]; then
echo "=== DRY RUN - No changes made ==="
exit 0
fi
# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Create a new orphan branch with squashed history
echo "=== Squashing history ==="
# Get the commit hash to start from (first commit to keep)
FIRST_KEPT_COMMIT=$(git rev-list --after="${CUTOFF_DATE}" HEAD | tail -1)
if [ -z "${FIRST_KEPT_COMMIT}" ]; then
FIRST_KEPT_COMMIT=$(git rev-parse HEAD)
fi
# Create orphan branch from the state before our retention period
# with all current files
git checkout --orphan temp-cleanup
# Stage all current files
git add -A
# Create initial squashed commit
git commit -m "chore: squash history (commits before ${CUTOFF_DATE})
This commit contains the squashed history of gh-pages branch.
Original commits before ${CUTOFF_DATE} have been combined to reduce repository size.
Squashed ${COMMITS_TO_SQUASH} commits.
🤖 Generated by cleanup-history workflow"
# Now cherry-pick the recent commits on top
if [ "${COMMITS_TO_KEEP}" -gt 0 ]; then
echo "Cherry-picking ${COMMITS_TO_KEEP} recent commits..."
RECENT_COMMITS=$(git rev-list --reverse --after="${CUTOFF_DATE}" gh-pages)
for commit in ${RECENT_COMMITS}; do
# Skip if this would result in empty commit
git cherry-pick --allow-empty "${commit}" || {
echo " Skipping commit ${commit} (likely empty or conflict)"
git cherry-pick --abort 2>/dev/null || true
}
done
fi
# Force update gh-pages
git branch -D gh-pages
git branch -m gh-pages
# Garbage collect
echo ""
echo "=== Running garbage collection ==="
git reflog expire --expire=now --all
git gc --prune=now --aggressive
NEW_SIZE=$(du -sh .git | cut -f1)
NEW_COMMITS=$(git rev-list --count HEAD)
echo ""
echo "=== Cleanup complete ==="
echo "Before: ${CURRENT_COMMITS} commits, ${CURRENT_SIZE}"
echo "After: ${NEW_COMMITS} commits, ${NEW_SIZE}"
- name: Push cleaned history
if: ${{ github.event.inputs.dry_run != 'true' }}
run: |
git push origin gh-pages --force
- name: Summary
run: |
if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
echo "## Dry Run Complete" >> $GITHUB_STEP_SUMMARY
echo "No changes were pushed." >> $GITHUB_STEP_SUMMARY
else
echo "## History Cleanup Complete" >> $GITHUB_STEP_SUMMARY
echo "The gh-pages branch history has been squashed." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Old commits have been combined into a single commit to reduce repository size." >> $GITHUB_STEP_SUMMARY
fi