Skip to main content
Dev Note

How to Archive Multiple GitHub Repos

Published by Josh Briley on December 28, 2025

It's the end of the year, which apparently means it's time for reflection and GitHub cleanup. Over the years, I've created (and quietly abandoned) a lot of repositories. Side projects. Experiments. "I'll totally finish this later" ideas. At some point I crossed the 100-repo mark, which made using the GitHub UI to clean things up feel like a punishment I didn't sign up for.

So instead of clicking my way into carpal tunnel, I did what any reasonable modern-day developer would do:

I asked ChatGPT to help me write a small bash script and let the computer do the boring part.

The goal was simple:

  • Archive old repos
  • Make them private
  • Preserve my todos, half-baked-sass ideas, fizzbuzzes and fibonacci experiments for historical reasons (Nostalgia? Maybe. Hoarder? Absolutely.)

Step 1: Install the GitHub CLI

If you're on a Mac and don't already have the GitHub CLI installed:

brew install gh

If you're on Windows, Google tells me this works:

winget install --id GitHub.cli

(I'll trust Google on this one.)

Step 2: Authenticate

Once installed, authenticate the CLI with your GitHub account:

gh auth login

Follow the prompts and you're good to go.

Step 3: Create the script

Create a new file called archive-repos.sh or whatever filename you prefer.

Here's the script I ended up with:

#!/usr/bin/env bash
# Use the user's env to find bash
set -euo pipefail
# Exit on error, unset vars are errors, fail pipelines on first failure

# Read each repository identifier (owner/repo) from repos.txt
while IFS= read -r r; do
  [[ -z "$r" ]] && continue
  # Skips empty lines

  echo "Checking $r"            # Progress output

  # Query current archived status and visibility via GitHub CLI (JSON + jq selector)
  archived=$(gh repo view "$r" --json isArchived --jq '.isArchived')
  visibility=$(gh repo view "$r" --json visibility --jq '.visibility')

  # 1) Ensure PRIVATE (even if archived)
  if [ "$visibility" != "PRIVATE" ]; then
    # If archived, temporarily unarchive to allow changing visibility
    if [ "$archived" = "true" ]; then
      echo "  → Repo is archived and not private. Temporarily unarchiving to change visibility..."
      gh repo unarchive "$r" --yes
      archived_was_true="true"
    else
      archived_was_true="false"
    fi

    echo "  → Setting visibility to private"
    # Change visibility to private; the flag auto-confirms the consequences prompt
    gh repo edit "$r" --visibility private --accept-visibility-change-consequences

    # If it was archived before, re-archive now that visibility is updated
    if [ "$archived_was_true" = "true" ]; then
      echo "  → Re-archiving"
      gh repo archive "$r" --yes
    fi
  else
    echo "  → Already private"
  fi

  # 2) Ensure archived (after visibility is correct)
  if [ "$archived" = "false" ]; then
    echo "  → Archiving"
    gh repo archive "$r" --yes
  else
    echo "  → Already archived"
  fi

done < repos.txt

Step 4: Tell the script what to clean up

Create a file called repos.txt (or whatever). This is just a list of repositories you want to archive, one per line, using the format owner/repo-name.

# repos.txt
your-github-username/repo1
your-github-username/repo2
your-github-username/repo3
# etc.

This makes it easy to add or remove repos without touching the script itself, which feels like the polite thing to do.

Yeh, yeh... I know.

That script could be refactored to include the GitHub username so you don't have to repeat it for each repo, but hey, this is a quick-and-dirty script.

Step 5: Run it

Make the script executable:

chmod +x archive-repos.sh

Then run it:

./archive-repos.sh

You'll see output something like this:

Checking your-github-username/repo1
 Setting visibility to private
 Archiving
Checking your-github-username/repo2
 Already private
 Already archived
Checking your-github-username/repo3
 Setting visibility to private
 Archiving

The script walks through each repository, makes it private if needed, and then archives it. No clicking. No UI fatigue. No second-guessing whether you really need that half-finished side project from 2017. Your GitHub stays tidy and your old experiments stay preserved. Everyone wins.

If nothing else, this is a good reminder that automation is just empathy for your future self.