Cleanup gh-pages History #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |