如何一次性从GitHub克隆所有仓库?

234

我有一个公司的GitHub账户,我想备份其中的所有存储库,同时考虑到为自动化目的创建的任何新内容。我希望有这样一个东西:

git clone git@github.com:company/*.git 

或类似的东西可能有效,但看起来它不喜欢通配符。

在Git中有没有一种方法可以假设拥有适当的权限,克隆然后拉取所有内容?


5
好问题。那么关于通过pull保持它们同步,有什么建议吗?这些回答中的任何一个适用于pull吗? - nealmcb
1
我们需要一个Python解决方案,对于那些不太擅长使用Node或Ruby的人来说;或者GitHub应该阅读此内容并怜悯我们,只需为此提供一个简单的Web界面.... - nealmcb
1
尝试一下:https://github.com/wballard/git-friends - kenorb
你可以使用ghorg,然后只需运行ghorg clone org --backup --clone-wiki --token=xxxx即可。 - jimjam
为了保持代码仓库同步,请参考 这个答案 - 可能还有其他方法。 - RichVel
48个回答

227

使用GitHub CLI(无需API密钥)的简单脚本

这是一个使用官方GitHub CLI工具gh的简单解决方案-无需API密钥,可以处理多达4,000个私有仓库。

仅需第一次:使用gh登录私有仓库,并按照提示操作:

gh auth login

现在你可以在一个新的./myorgname文件夹下克隆任意数量的仓库。将myorgname替换为你的组织名称:
gh repo list myorgname --limit 4000 | while read -r repo _; do
  gh repo clone "$repo" "$repo"
done

默认限制是30。
这在Mac或Linux上应该可以工作。
在Windows上呢?
WSL或Git Bash中运行此脚本,这是Git for Windows的一部分。
或者尝试@Karson在PowerShell中提供的类似脚本的评论。
设置
获取GitHub CLI工具
Mac - brew install gh Linux或Windows - 参见GitHub安装指南 未来的保护:GitHub CLI工具将长期支持,并随着GitHub API的变化而更新。一些旧的答案可能因此不再有效。
可选:更新现有的检出
为了更新已经存在于磁盘上的仓库文件夹,以及克隆新的仓库,脚本需要检查gh repo clone的失败情况,就像这样:
gh repo list myorgname --limit 1000 | while read -r repo _; do
  gh repo clone "$repo" "$repo" -- -q 2>/dev/null || (
    cd "$repo"
    # 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

小贴士

  • 不想在./myorgname文件夹中创建仓库?在gh repo clone命令中省略第二个"$repo"参数,即可在当前目录中创建。

筛选结果:

  • --no-archived - 不显示已存档的仓库
  • --source - 仅显示非派生仓库

小贴士:处理成千上万个仓库

这个脚本可以处理多达约4,000个仓库 - 参见@Ryan Fisher的评论,并在评论中分享您的结果。

gh repo list命令使用GitHub搜索API,在返回大量结果时进行分页。搜索的仓库数量有上限为4,000

为了解决任何限制:

  • 检查gh repo list命令是否返回您所期望的结果
  • 确保您省略了存档和派生的存储库
  • 使用gh repo list --help命令来按语言、主题等进行过滤

或者您可以使用基于API请求的不同答案,替换gh repo list命令或整个脚本。

提示:对于许多存储库的更快克隆

如果您要克隆大量存储库,可以使用GNU parallel来加快此脚本的速度。

gh repo list <ORG_NAME> --limit <LIMIT> --json nameWithOwner --jq '.[].nameWithOwner' | \
   parallel -j<JOBS> gh repo clone

这里使用的是gh的内部jq库,而不是独立的jq
如果您使用上面的“更新现有检出”选项,您将需要将其合并到上面的脚本中-可能将循环内容放入parallel下的单独的bash -c "..."命令中。
您还可以使用xargs -P并行克隆存储库-请参阅this answer

背景


12
我认为这是一个非常好的解决方案。我今天早上大部分时间都在做这个(使用gh编写解决方案),因为我没能找到第二页的答案。希望这个解决方案能得到赞同,以便其他人不会重复同样的错误。 - Pranasas
6
迄今为止,最容易实施的解决方案。 - Ketouem
4
这个解决方案非常干净。我想知道是否也能轻松地拉取每个仓库的所有远程分支。 - Taylor D. Edmiston
2
@TaylorD.Edmiston 参见此答案,了解克隆所有分支的方法,并使用git branch -a查看它们。正常的git clone包括远程跟踪分支。您可以在主脚本的gh repo clone之后添加命令,例如:( cd "$repo" && COMMANDS_HERE ) - 括号创建子shell以限制cd的范围。请注意git push - 默认情况下会推送所有分支:评论 - RichVel
1
@RyanFisher 谢谢,我在回答中做了一个备注。我不认为公共/私有或SSH会改变限制,所以这是个好消息! - undefined
显示剩余10条评论

188
在 Windows 和所有 UNIX/LINUX 系统上,使用 Git Bash 或任何其他终端,将您的 USERNAME 替换为您的用户名,然后使用以下命令:
CNTX={users|orgs}; NAME={username|orgname}; PAGE=1
curl "https://api.github.com/$CNTX/$NAME/repos?page=$PAGE&per_page=100" |
  grep -e 'clone_url*' |
  cut -d \" -f 4 |
  xargs -L1 git clone
  • 设置CNTX=usersNAME=yourusername,以下载您所有的存储库。
  • 设置CNTX=orgsNAME=yourorgname,以下载您组织的所有存储库。

最大页面大小为100,因此您必须使用正确的页面编号多次调用此函数以获取所有存储库(将PAGE设置为要下载的所需页面编号)。

以下是执行上述操作的shell脚本: https://gist.github.com/erdincay/4f1d2e092c50e78ae1ffa39d13fa404e


7
纯 Bash 解决方案,非常简单。需要说明的是,这个 Bash 代码可以在几乎所有*nix环境中执行,包括Linux、Cygwin、Mingw和Gitbash,后者实际上像其他终端仿真器一样。 - m3nda
3
使用认证: curl "https://api.github.com/$CNTX/$NAME/repos?page=$PAGE&per_page=100&access_token=$ACCESS_TOKEN" | grep -e 'git_url*' | cut -d " -f 4 | xargs -L1 git clone - Yannick Wurm
5
请更新答案(2019年2月):根据 GitHub API v3,您的 curl 应该转到 /orgs/ORGNAME/repos。另外,可能要包括 API v3 的链接:https://developer.github.com/v3/。另外,对于私有仓库,您需要添加 curl -u“用户名”,然后 curl 会要求您输入密码。否则工作得非常好!:))) - Dmitry Shevkoplyas
3
来自dimitry hevkoplyas在stackoverflow评论中的更新 https://dev59.com/H2Ik5IYBdhLWcg3wG63b#zLejEYcBWogLw_1bgTVl。当尝试使用curl时,developer.github.com/v3 返回301状态。使用以下bash命令:curl -u "{username}" "https://api.github.com/orgs/{org}/repos?page=1&per_page=100" | grep -o 'git@[^"]*' | xargs -L1 git clone可以正常工作100%。 - Tommy
3
这只能获取公共仓库,而不能获取私有和内部仓库。 - wogsland
显示剩余8条评论

73

我认为用这种方式做不可能。你最好的选择是使用API查找并循环遍历一个组织的库列表。

请尝试以下步骤:

  • 通过前往“账户设置”->“应用程序”创建一个API令牌
  • 调用:http://${GITHUB_BASE_URL}/api/v3/orgs/${ORG_NAME}/repos?access_token=${ACCESS_TOKEN}
  • 响应将是一个JSON对象数组,每个对象都包含关于该组织下一个存储库的信息。在您的情况下,我认为您将特别寻找ssh_url属性。
  • 然后,对每个ssh_url进行git clone操作。

这需要一些额外的工作,但为了在GitHub上拥有适当的身份验证,这是必要的。


1
这是一个 GitHub Enterprise 账户,还是 github.com? - Thomas Kelley
2
啊,我误解了你的意思。我以为这是一个企业账户。请尝试使用 https://api.github.com/ 而不是 https://github.com/api/v3/ - Thomas Kelley
2
我不确定你们公司的具体设置,但如果它是一个“用户”而不是一个“组织”,那么你将需要使用/users/${COMPANY}/repos路径而不是/orgs/${COMPANY}/repos - Thomas Kelley
2
如果您喜欢使用命令行界面,ghorg 可以为您完成此任务。 - jimjam
3
根据 GitHub 的提示,请使用授权HTTP头部代替access_token查询参数,因为该查询参数已被弃用。如果该令牌被您无法控制的应用程序使用,请注意由于此弃用可能导致其停止工作。 - BogeyMan
显示剩余6条评论

71

机构代码库

要克隆您机构的所有代码库,请尝试使用以下 shell 一行命令:

GHORG=company; curl "https://api.github.com/orgs/$GHORG/repos?per_page=1000" | grep -o 'git@[^"]*' | xargs -L1 git clone

用户代码库

使用Git仓库URL克隆全部:

GHUSER=CHANGEME; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000" | grep -o 'git@[^"]*' | xargs -L1 git clone

使用克隆URL进行全部克隆:

GHUSER=CHANGEME; curl "https://api.github.com/users/$GHUSER/repos?per_page=1000" | grep -w clone_url | grep -o '[^"]\+://.\+.git' | xargs -L1 git clone

这是一个有用的shell函数,可以添加到用户的启动文件中(使用curl + jq):

# Usage: gh-clone-user (user)
gh-clone-user() {
  curl -sL "https://api.github.com/users/$1/repos?per_page=1000" | jq -r '.[]|.clone_url' | xargs -L1 git clone
}

私有代码库

如果你需要克隆私有代码库,你可以在请求头中添加授权令牌(Authorization token),例如:

-H 'Authorization: token <token>'

或者将其作为参数传递(?access_token=TOKEN),例如:

curl -s "https://api.github.com/users/$GHUSER/repos?access_token=$GITHUB_API_TOKEN&per_page=1000" | grep -w clone_url | grep -o '[^"]\+://.\+.git' | xargs -L1 git clone

注意事项:

  • 如果只想获取私有仓库,可以在查询字符串中添加type=private
  • 另一种方法是在配置API密钥后使用hub工具。

参见:


提示:
- 为提高速度,可通过为xargs指定-P参数设置并行进程数(-P4 = 4个进程)。
- 如果需要增加GitHub限制,请尝试通过指定API密钥进行身份验证。
- 添加--recursive选项以递归到已注册的子模块,并更新其中的任何嵌套子模块。


6
每页显示1000个的per_page参数最多只能到100个。 - aehlke
如果这不是你自己的组织,请尝试添加以下内容:sed 's/git@github.com:/https:\/\/github.com\//g',如下所示:curl "GHORG=company; https://api.github.com/orgs/$GHORG/repos?per_page=1000" | grep -o 'git@[^"]*' | sed 's/git@github.com:/https:\/\/github.com\//g' | xargs -L1 git clone - root
我修改了正则表达式,因为我没有设置SSH密钥,所以出现了以下错误:git@github.com: Permission denied (publickey)。修改后的命令:GHORG=company; curl "https://api.github.com/orgs/$GHORG/repos?per_page=1000" | grep -o "https://github.com/$GHORG/.*.git\b" | xargs -L1 git clone - Ram

25

这个代码片段可以在命令行中用一行命令完成任务:


curl -s https://api.github.com/orgs/[your_org]/repos?per_page=200 | ruby -rubygems -e 'require "json"; JSON.load(STDIN.read).each { |repo| %x[git clone #{repo["ssh_url"]} ]}'

请将[your_org]替换为您的组织名称。如有需要,请设置您的per_page

更新:

正如ATutorMe所提到的,根据GitHub文档最大页面大小为100

如果您有超过100个存储库,则必须向您的url添加一个page参数,并可以为每个页面运行命令。

curl -s "https://api.github.com/orgs/[your_org]/repos?page=2&per_page=100" | ruby -rubygems -e 'require "json"; JSON.load(STDIN.read).each { |repo| %x[git clone #{repo["ssh_url"]} ]}'

注意:默认的per_page参数是30


1
你有没有想过如何在你有权限访问的私有仓库中实现这个功能? - MichaelGofron
1
第二个不起作用是因为“&”符号使其成为后台任务。 - slashdottir
1
我在URL中添加了&access_token=<my_access_token>,它完美地工作了。 - rmartinus
1
第二个:page=1 (!) - Yannick Wurm
1
根据其他答案的评论,per_page参数的最大值为100,您可以输入任何更大的数字,但是您只会获得100个存储库。 - Mikhail Chibel

16

仍然是2023年最佳解决方案:

首先,安装这个。

gh extension install matt-bartel/gh-clone-org

然后这是一个非常简单的命令来实现这个目标。
gh clone-org my_org_name

Github CLI现在有一个扩展这里。第一个命令来自这里。

这个扩展可以通过组织名称来克隆和更新现有的仓库。

建议从Github CLI的问题列表这里获取。


超级简单的解决方案!谢谢! - ckuijjer
运行得很好 - 干得好! - James Morgan
更简单的方式..我在其他方式中遇到了问题 - Nabeel
这个命令是否也会克隆所有的分支? - undefined

11
使用Github CLI结合一些脚本,可以克隆命名空间下的所有(公共或私人)存储库。
gh repo list OWNER --limit 1000 | awk '{print $1; }' | xargs -L1 gh repo clone

其中 OWNER 可以是您的用户名或组织名。


2
这里 - 远远是最简单和最新的方法 - bogdan.css

9
所以,我也会添加我的答案。 :)(我发现这很简单)
获取列表(我使用了“magento”公司):
curl -si https://api.github.com/users/magento/repos | grep ssh_url | cut -d '"' -f4

使用clone_url而不是ssh_url以使用HTTP访问。

所以,让我们克隆它们全部! :)

curl -si https://api.github.com/users/magento/repos | \
    grep ssh_url | cut -d '"' -f4 | xargs -i git clone {}

如果您要获取私有仓库,只需添加GET参数?access_token=YOURTOKEN

8

前往“账户设置”->“应用程序”,创建一个API密钥
然后在以下脚本中插入API密钥、GitHub实例URL和组织名称。

#!/bin/bash

# Substitute variables here
ORG_NAME="<ORG NAME>"
ACCESS_TOKEN="<API KEY>"
GITHUB_INSTANCE="<GITHUB INSTANCE>

URL="https://${GITHUB_INSTANCE}/api/v3/orgs/${ORG_NAME}/repos?access_token=${ACCESS_TOKEN}"

curl ${URL} | ruby -rjson -e 'JSON.load(STDIN.read).each {|repo| %x[git clone #{repo["ssh_url"]} ]}'

把它保存在一个文件中,chmod u+x给文件加上可执行权限,然后运行它。

感谢Arnaud提供的Ruby代码。


这里的 GITHUB_INSTANCE 是什么? - Happy Coder

7
这个Python单行代码可以满足你的需求。它能够:
  • checks github for your available repos
  • for each, makes a system call to git clone

    python -c "import json, urllib, os; [os.system('git clone ' + r['ssh_url']) for r in json.load(urllib.urlopen('https://api.github.com/orgs/<<ORG_NAME>>/repos?per_page=200'))]"
    

2
对于Python3,请使用以下命令:python -c "import json, urllib.request, os; [os.system('git clone ' + r['clone_url']) for r in json.load(urllib.request.urlopen('https://api.github.com/orgs/<<ORG_NAME>>/repos?per_page=200'))]" - thisisbhavin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接