Skip to content

Instantly share code, notes, and snippets.

@cassc
Created July 18, 2023 02:38
Show Gist options
  • Save cassc/169c81133b4ac3d96348c171f9fae353 to your computer and use it in GitHub Desktop.
Save cassc/169c81133b4ac3d96348c171f9fae353 to your computer and use it in GitHub Desktop.
Clone all github repos
# python github-clone-by-user.py username --skip-forks --excluded project1 project2
import requests
import subprocess
import argparse
import os
def clone_or_fetch_repo(username, token, skip_forks):
headers = {'Authorization': f'token {token}'} if token else {}
# First, clone or fetch the public repositories of the specified user
base_url = f"https://api.github.com/users/{username}/repos"
clone_or_fetch(base_url, headers, username, skip_forks)
if not token:
return
# Then, clone or fetch the repositories that the authenticated user has access to
base_url = "https://api.github.com/user/repos"
clone_or_fetch(base_url, headers, username, skip_forks)
def clone_or_fetch(base_url, headers, username, skip_forks):
page = 1
while True:
# Add the page and per_page parameters to the URL
url = f"{base_url}?page={page}&per_page=100"
# Send a GET request to the GitHub API
response = requests.get(url, headers=headers)
# If the request was successful
if response.status_code == 200:
# Get the JSON data from the response
repos = response.json()
# If there are no repositories in the response, we've reached the end of the list
if not repos:
break
# For each repository
for repo in repos:
if skip_forks and repo.get('fork'):
print(f"Skipping forked repo {repo['name']}")
continue
# Get the SSH URL
clone_url = repo["ssh_url"]
# Get the repository name
repo_name = repo["name"]
repo_owner = repo["owner"]["login"]
if repo_owner != username:
continue
if repo_name in excluded:
continue
# Check if the repository already exists
if os.path.exists(repo_name):
# If it does, fetch the updates
subprocess.run(["git", "-C", repo_name, "fetch"])
else:
# If it doesn't, clone the repository
subprocess.run(["git", "clone", clone_url])
# Go to the next page
page += 1
else:
print(f"Failed to get repositories. Status code: {response.status_code}")
break
# Create the parser
parser = argparse.ArgumentParser(description="Clone all repositories that the authenticated user has access to, from a specific GitHub user")
# Add the arguments
parser.add_argument('username', type=str, help="The GitHub username")
parser.add_argument('token', type=str, nargs='?', default=None, help="The GitHub personal access token (optional)")
parser.add_argument('--skip-forks', action='store_true', help="Whether to skip forked repositories (optional)")
parser.add_argument('--excluded', nargs='*', default=[], help="List of repository names to be excluded (optional)")
# Parse the arguments
args = parser.parse_args()
excluded = set(args.excluded)
# Call the function with the username and token arguments
clone_or_fetch_repo(args.username, args.token, args.skip_forks)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment