Skip to content

Instantly share code, notes, and snippets.

@caniszczyk
Created October 9, 2012 04:25
Show Gist options
  • Save caniszczyk/3856584 to your computer and use it in GitHub Desktop.
Save caniszczyk/3856584 to your computer and use it in GitHub Desktop.
Clone all repos from a GitHub organization
curl -s https://api.github.com/orgs/twitter/repos?per_page=200 | ruby -rubygems -e 'require "json"; JSON.load(STDIN.read).each { |repo| %x[git clone #{repo["ssh_url"]} ]}'
@steven-lai
Copy link

Credit to @clrung for the initial version. Minor differences:

  • This will stop once it has iterated through all the repos (curl returns nothing)
  • Added some minor logging
  • Added ability to ignore repos
  • Added repo type (e.g. public or private)
  • Added ability to do test run (no actual cloning)
  • Added some variation of git-clone (e.g. shallow) if you need it

Fill out ORG and TOKEN.

#!/bin/bash

# Modified version of https://gist.github.com/caniszczyk/3856584#gistcomment-3157288

# Sample syntax:
#   foobar\.git
#   foobar\.git|helloworld\.git
IGNORED_REPO=""
IGNORED_REPO_COUNT=0

ORG="TODO"

# per_page maxes out at 100
PER_PAGE=100

REPO_TYPE="private"

TOKEN="TODO"

TEST_RUN=false

for ((PAGE=1; ; PAGE+=1)); do
  # Page 0 and 1 are the same
  # Change authorization method as needed
  INPUT=$(curl -H "Authorization: token $TOKEN" -s "https://api.github.com/orgs/$ORG/repos?type=$REPO_TYPE&per_page=$PER_PAGE&page=$PAGE" | jq -r ".[].clone_url")
  if [[ -z "$INPUT" ]]; then
    echo "All repos processed, ignored $IGNORED_REPO_COUNT repo(s) and stopped at page=$PAGE"
    exit
  fi
  while read REPO_URL ; do
    if [[ "$REPO_URL" =~ $IGNORED_REPO ]]; then
      echo "*** IGNORING $REPO_URL"
      IGNORED_REPO_COUNT=$((IGNORED_REPO_COUNT+1))
    else
      if $TEST_RUN; then
        echo "git clone $REPO_URL"
      else
        #git clone "$REPO_URL" >/dev/null 2>&1 ||   # Pipe stdout and stderr to /dev/null
        #git clone --depth 1 "$REPO_URL" ||         # Shallow clone for faster cloning, within the repo use the following to get the full git history: git pull --unshallow
        git clone "$REPO_URL" ||                    # Vanilla
          { echo "ERROR: Unable to clone $REPO_URL!" ; continue ; }
      fi
    fi
# This syntax works as well /shrug
#  done <<< "$INPUT"
  done < <(echo "$INPUT")
done

Feedback welcome!

@cruizba
Copy link

cruizba commented Jul 15, 2020

Why do you overcomplicate yourselfs using a lot of stuff, languages and tools? A simple command using bash:

for repo in $(curl -s -iH "Authorization: token ${ACCESS_TOKEN}" https://api.github.com/orgs/${ORG_NAME}/repos?per_page=200 | grep ssh_url | rev | cut -d'"' -f2 | rev); do git clone $repo; done

You only need to export ACCESS_TOKEN and ORG_NAME

@steven-lai
Copy link

I need the ability to filter and do more than just a single page which is a max 200 repo. Using jq is far more future proof than using cut if the results are changed.

@rainb3rry
Copy link

curl -s https://api.github.com/orgs/<ORG_NAME>/repos\?per_page\=100 | jq '.[].html_url' | xargs -n 1 git clone

Thanks man

@AchmadFathoni
Copy link

Is there any way to fork instead of clone all repositories in an organization?

@steven-lai
Copy link

@llewxam-kache
Copy link

Why do you overcomplicate yourselfs using a lot of stuff, languages and tools? A simple command using bash:

for repo in $(curl -s -iH "Authorization: token ${ACCESS_TOKEN}" https://api.github.com/orgs/${ORG_NAME}/repos?per_page=200 | grep ssh_url | rev | cut -d'"' -f2 | rev); do git clone $repo; done

You only need to export ACCESS_TOKEN and ORG_NAME

Excellent work, much appreciated.

@flavioespinoza
Copy link

flavioespinoza commented Apr 19, 2021

Create a bash alias/func in your ~/.bashrc or ~/.zshrc file

I solved this for my team by creating an alias/bash func in the ~/.bashrc or ~/.zshrc configuration file.

Config

MacOS Terminal

Open a new Terminal and edit your .bashrc configuration file:

sudo nano ~/.bashrc

-- or --

MacOS iTerm2 with oh-my-zsh

Open iTerm2 terminal and edit your .zshrc configuration file:

sudo nano ~/.zshrc

Create CloneAll Func

Add the following bash func as an alias:

CloneAll() {
    # Make the url to the input github organization's repository page.
    ORG_URL="https://api.github.com/orgs/${1}/repos?per_page=200";

    # List of all repositories of that organization (seperated by newline-eol).
    ALL_REPOS=$(curl -s ${ORG_URL} | grep html_url | awk 'NR%2 == 0' \
                | cut -d ':' -f 2-3 | tr -d '",');

    # Clone all the repositories.
    for ORG_REPO in ${ALL_REPOS}; do
        git clone ${ORG_REPO}.git;
    done
}

.bashrc

Save and close your ~/.bashrc file and then close the terminal, then open a new one.

You need to do this or the new alias won't initialize:

-- or --

.zshrc

Save and close your ~/.zshrc file and run the following command:

exec "$SHELL"

Run

CloneAll <your_github_org_name>

Example

If your GitHub repo URL is called https://github.com/flavioespinoza the command would be:

CloneAll flavioespinoza

Troubleshooting

Set Number of Repos to Clone

The per_page=200 at the end of the first variable ORG_URL sets the number of repos that will be cloned

ORG_URL="https://api.github.com/orgs/${1}/repos?per_page=<number_of_repos>";  <---- make sure this is what you want

@askfriends
Copy link

How to run this on Windows10?
btw i want to clone/download all my own repos which include 3 or 4 private repos too.

@Gesugao-san
Copy link

@l0b0
Copy link

l0b0 commented Sep 6, 2021

Parallel, properly paginated (100 per page is max) SSH cloning of public and private org repos - just provide $TOKEN and $ORG:

page=1
while links=($(curl -H "Authorization: token ${TOKEN}" -s "https://api.github.com/orgs/${ORG}/repos?per_page=100&page=${page}" | jq -rc '.[] | {ssh_url} | .ssh_url'));  [[ "$links" ]]
do
    GIT_TERMINAL_PROMPT=0 parallel git clone --depth=1 {} ::: "${links[@]}"
    ((++page))
done

@redaphid
Copy link

I just want to say that this thread is a great example of the open source community. An 8-year thread on a platform, with everybody posting little bits of code and share with others for free, on the platform itself.

@redaphid
Copy link

redaphid commented Dec 18, 2021

I just finished up a simple script if you have a similar oddball setup to me (jq,gh,fish shell). Fish is just used because I like the scripting language. (Not that I'm defensive about fish or anything. haha)

#!/usr/bin/env fish
# You need:
# - fish (https://fishshell.com/) (You don't need to use it as your shell, but it's a good shellscripting language)
# - gh - github cli (https://cli.github.com)
# - jq (https://stedolan.github.io/jq/)

set -q ORG[1]; or begin
	echo "I need the org name! I use the environment variable $ORG. example: ORG=octoblu ./download.fish" >&2
	exit 1
end

set repos (gh repo list $ORG --limit 9999 --json name)
set repos_to_clone (echo $repos | jq -r ".[].name")

echo "cloning repos:\n $repos_to_clone"
for u in $repos_to_clone
	echo "cloning $u"
	git clone https://github.com/$ORG/$u repos/$u; or echo "failed to clone $u"
	sleep 5
end

@redaphid
Copy link

redaphid commented Dec 19, 2021

fwiw you can also fork all the repos in an org to a new org like this:

#!/usr/bin/env fish
# You need:
# - fish (https://fishshell.com/) (You don't need to use it as your shell, but it's a good shellscripting language)
# - gh - github cli (https://cli.github.com)
# - jq (https://stedolan.github.io/jq/)

set -q OLD_ORG[1]; or begin
	echo "I need the org name! I use the environment variable $OLD_ORG. example: OLD_ORG=octoblu NEW_ORG=meshnu ./fork.fish" >&2
	exit 1
end

set -q NEW_ORG[1]; or begin
	echo "I need the org name! I use the environment variable $NEW_ORG. example: OLD_ORG=octoblu NEW_ORG=meshnu ./fork.fish" >&2
	exit 1
end

set repos (gh repo list $OLD_ORG --limit 9999 --json name)
set repos_to_clone (echo $repos | jq -r ".[].name")

echo "cloning repos:\n $repos_to_clone"
for u in $repos_to_clone
	echo "forking $u"
	gh repo fork $OLD_ORG/$u --clone=false --org $NEW_ORG; or echo "failed to clone $u"
	sleep 5
end

# echo $repos

@gabrie30
Copy link

@askfriends ghorg will work on Windows and allows you to clone your own repos as well as from an org

@patrickdevivo
Copy link

This can also be done with a tool called mergestat, as described on this page of the docs.

For example like so:

mergestat "SELECT clone('https://github.com/mergestat/'|| name) AS path FROM github_org_repos('mergestat')" -v --clone-dir my-dir

An advantage of this approach is that pagination and API rate limits are taken care of by the tool, and arbitrary "sets" of repos can be cloned (filter out by certain criteria such as age or language).

Full disclosure, I am the maintainer/creator of mergestat, but wanted to share as this is a fairly frequent use-case/question we receive from people looking to batch query/work with repos belonging to an org.

@doleron
Copy link

doleron commented Jan 24, 2022

Well, I used this repo: https://github.com/muhasturk/gitim

python3 -m gitim -o my_org -t mytoken

@mirstan
Copy link

mirstan commented Jan 29, 2022

Thanks for all the hints. This worked for me and assumes that you've installed gh and jq then authenticated using gh auth login :
gh repo list $ORG --limit 9999 --json sshUrl | jq '.[]|.sshUrl' | xargs -n1 git clone

@ChaitanyaChandra
Copy link

clone all repos

  • you need to install gh (github api)
  • windows : choco install gh
  • mac : brew install gh
username="ChaitanyaChandra" # user name or org name is required
limit=100
gh repo list $username --limit $limit | awk '{print $1}' > out.txt
while read -r line; do echo "git clone  https://github.com/$line.git" >> final.sh  ; done < out.txt
chmod +x final.sh
./final.sh

@aclk
Copy link

aclk commented Mar 4, 2022

  • Into $ORG folder
    mkdir $ORG; cd $ORG
  • Loop clone repo
    gh repo list $ORG --limit 9999 --json url | jq '.[]|.url' | xargs -n1 git clone

@ahmed2m
Copy link

ahmed2m commented May 14, 2022

  • Into $ORG folder
    mkdir $ORG; cd $ORG
  • Loop clone repo
    gh repo list $ORG --limit 9999 --json url | jq '.[]|.url' | xargs -n1 git clone

Github stopped https clones (username and passwords needed for every clone so instead use ssh clone
gh repo list $ORG --limit 9999 --json sshUrl | jq '.[]|.sshUrl' | xargs -n1 git clone

@RTC1
Copy link

RTC1 commented Jun 29, 2022

This also works whilst using gh command and auth instead of git

gh repo list $ORG --limit 9999 --json nameWithOwner | jq '.[]|.nameWithOwner' | xargs -n1 gh repo clone

@sikmir
Copy link

sikmir commented Oct 7, 2022

this can be even simpler, assuming < 100 repos: curl -s https://api.github.com/orgs/<ORG_NAME>/repos\?per_page\=100 | jq '.[].html_url' | xargs -n 1 git clone

Just in case, if you need ssh url and a bit more than 100 repos:
curl -s "https://api.github.com/orgs/<ORG_NAME>/repos?per_page=100&page=<1,2...>" | jq '.[].ssh_url' | xargs -n 1 git clone

@Danipulok
Copy link

Hi all
I wrote a simple script to clone all the repositories from GitHub, either from a user or whole organization. Please check it out, I'm sure you'll find it useful

@octohedron
Copy link

Here's a fully working script with things from here, SO + some improvements by me. Needs gh cli.

If the repo exists it will check out the main/master branch and pull.

#!/bin/bash

ORG="myorg" # Your organization
CLONE_PATH="/home/user/Documents/..." # Path in your filesystem where you want to clone the repos
PER_PAGE=100 # per_page maxes out at 100
TOKEN="" # Set your token from GH

for ((PAGE=1; ; PAGE+=1)); do
  # Page 0 and 1 are the same
  # Change authorization method as needed
  INPUT=$(curl -H "Authorization: token $TOKEN" -s "https://api.github.com/orgs/$ORG/repos?per_page=$PER_PAGE&page=$PAGE" | jq -r ".[].clone_url")
  if [[ -z "$INPUT" ]]; then
    echo "All repos processed, stopped at page=$PAGE"
    exit
  fi
  while read REPO_URL ; do
    echo $REPO_URL
    temp=${REPO_URL##*/}
    repo_name=${temp%.*}
    gh repo clone "$REPO_URL" "$CLONE_PATH/$repo_name" -- -q 2>/dev/null || (
        cd "$CLONE_PATH/$repo_name"
        # Handle case where local checkout is on a non-main/master branch
        # - ignore checkout errors because some repos may have zero commits, 
        # so no main or master
        git checkout -q main 2>/dev/null || true
        git checkout -q master 2>/dev/null || true
        git pull -q
    )
  done < <(echo "$INPUT")
done

@ology
Copy link

ology commented Nov 4, 2023

And here's a "Perl-as-glue" version, that works on systems with command-line curl and git: https://gist.github.com/ology/b6087be12131bae0441d40d87505e658 :D

@Vaisakhkm2625
Copy link

Vaisakhkm2625 commented Jan 15, 2024

  • | xargs -n1 git clone

we can essentially remove jq and directly use gh

gh repo list --json=sshUrl --limit 1000 -q ".[].sshUrl" | xargs -n1 git clone

though, it's asking for ssh passcode... any idea how to overcome that?

@hotelzululima
Copy link

hotelzululima commented Jan 16, 2024 via email

@Vaisakhkm2625
Copy link

meh.. I have moved to ghorg. implemented it does everything I could do with my own scripts and is 10 times as fast to boot gh

On Mon, Jan 15, 2024 at 10:23 AM Vaisakh K M @.> wrote: @.* commented on this gist. ------------------------------ - | xargs -n1 git clone we can essentially remove jq and directly use gh gh repo list --json=sshUrl --limit 1000 -q ".[].sshUrl" | xargs -n1 git clone — Reply to this email directly, view it on GitHub https://gist.github.com/caniszczyk/3856584#gistcomment-4832274 or unsubscribe https://github.com/notifications/unsubscribe-auth/ABNZZRED6QI6M2V6ZDBT4XTYOVXZXBFKMF2HI4TJMJ2XIZLTSKBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDHNFZXJJDOMFWWLK3UNBZGKYLEL52HS4DFVRZXKYTKMVRXIX3UPFYGLK2HNFZXIQ3PNVWWK3TUUZ2G64DJMNZZDAVEOR4XAZNEM5UXG5FFOZQWY5LFU4ZTQNJWGU4DJJ3UOJUWOZ3FOKTGG4TFMF2GK . You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub .

thanks.. i didn't know that existed...

@davidglezz
Copy link

Windows / PowerShell

gh repo list theUSERorORG --json=nameWithOwner --limit 1000 -q ".[].nameWithOwner"  | %{gh repo clone $_}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment