如何在 GitLab 一次性克隆一个团队的所有项目?

在我的 GitLab 知识库中,我有一个拥有20个项目的小组。我想一次性克隆所有项目。这可能吗?

142237 次浏览

没有,除非:

  • 你有一个21世纪的项目,其中参考其他20作为 子模组
    (在这种情况下,一个克隆后跟一个 git submodule update --init就足以让所有20个项目都被克隆和检查出来)

  • 或者以某种方式列出您可以访问的项目(用于项目的 GitLab API) ,然后循环该结果以克隆每个项目(这意味着可以编写脚本,然后作为“ one”命令执行)


自2015年以来,Jay Gabez提到了 在评论中(2019年8月)工具 gabrie30/ghorg

ghorg允许您将组织或用户的所有回购协议快速克隆到单个目录中。

用法:

$ ghorg clone someorg
$ ghorg clone someuser --clone-type=user --protocol=ssh --branch=develop
$ ghorg clone gitlab-org --scm=gitlab --namespace=gitlab-org/security-products
$ ghorg clone --help

另外(2020) : https://github.com/ezbz/gitlabber

usage: gitlabber [-h] [-t token] [-u url] [--debug] [-p]
[--print-format {json,yaml,tree}] [-i csv] [-x csv]
[--version]
[dest]


Gitlabber - clones or pulls entire groups/projects tree from gitlab

下面是 Python 3中的一个例子:

from urllib.request import urlopen
import json
import subprocess, shlex


allProjects     = urlopen("https://[yourServer:port]/api/v4/projects?private_token=[yourPrivateTokenFromUserProfile]&per_page=100000")
allProjectsDict = json.loads(allProjects.read().decode())
for thisProject in allProjectsDict:
try:
thisProjectURL  = thisProject['ssh_url_to_repo']
command     = shlex.split('git clone %s' % thisProjectURL)
resultCode  = subprocess.Popen(command)


except Exception as e:
print("Error on %s: %s" % (thisProjectURL, e.strerror))

有一个名为 我的回报的工具,它管理多个版本控制存储库。更新所有存储库只需要一个命令:

mr update

为了将所有的 gitlab 项目注册到 Mr,这里有一个小的 python 脚本。它需要安装包 巨蟒 Gitlab:

import os
from subprocess import call
from gitlab import Gitlab


# Register a connection to a gitlab instance, using its URL and a user private token
gl = Gitlab('http://192.168.123.107', 'JVNSESs8EwWRx5yDxM5q')
groupsToSkip = ['aGroupYouDontWantToBeAdded']


gl.auth() # Connect to get the current user


gitBasePathRelative = "git/"
gitBasePathRelativeAbsolut = os.path.expanduser("~/" + gitBasePathRelative)
os.makedirs(gitBasePathRelativeAbsolut,exist_ok=True)


for p in gl.Project():
if not any(p.namespace.path in s for s in groupsToSkip):
pathToFolder = gitBasePathRelative + p.namespace.name + "/" + p.name
commandArray = ["mr", "config", pathToFolder, "checkout=git clone '" + p.ssh_url_to_repo + "' '" + p.name + "'"]
call(commandArray)


os.chdir(gitBasePathRelativeAbsolut)


call(["mr", "update"])

你可以在这里参考这个红宝石脚本: Https://gist.github.com/thegauraw/da2a3429f19f603cf1c9b3b09553728b

但是您需要确保您拥有到组织 gitlab URL 的链接(例如,它看起来像: https://gitlab.example.com/api/v3/)和私有令牌(它看起来像: QALWKQFAGZDWQYDGHADS,一旦您登录,您就可以进入: https://gitlab.example.com/profile/account)。还要确保安装了 httparty gem 或 gem install httparty

我为此构建了一个脚本(curl,git,jq) ,我们使用它,它工作得很好: https://gist.github.com/JonasGroeger/1b5155e461036b557d0fb4b3307e1e75

要找到您的名称空间,最好快速检查 API:

curl "https://domain.com/api/v3/projects?private_token=$GITLAB_PRIVATE_TOKEN"

在那里,使用“ namespace.name”作为组的 NAMESPACE

剧本本质上是这样的:

  1. 获取与 PROJECT_SEARCH_PARAM匹配的所有项目
  2. 找到他们的 pathssh_url_to_repo

    2.1. 如果目录 path存在,则 cd 到目录中并调用 git pull

    2.2. 如果目录 path不存在,请调用 git clone

下面是 bash 脚本的另一个示例,用于克隆一个组中的所有回购协议。您需要安装的唯一依赖项是 jq (https://stedolan.github.io/jq/)。只需将脚本放入要将项目克隆到的目录中。然后运行如下:

./myscript <group name> <private token> <gitlab url>

也就是说。

./myscript group1 abc123tyn234 http://yourserver.git.com

剧本:

#!/bin/bash
if command -v jq >/dev/null 2>&1; then
echo "jq parser found";
else
echo "this script requires the 'jq' json parser (https://stedolan.github.io/jq/).";
exit 1;
fi


if [ -z "$1" ]
then
echo "a group name arg is required"
exit 1;
fi


if [ -z "$2" ]
then
echo "an auth token arg is required. See $3/profile/account"
exit 1;
fi


if [ -z "$3" ]
then
echo "a gitlab URL is required."
exit 1;
fi


TOKEN="$2";
URL="$3/api/v3"
PREFIX="ssh_url_to_repo";


echo "Cloning all git projects in group $1";


GROUP_ID=$(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups?search=$1 | jq '.[].id')
echo "group id was $GROUP_ID";
curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$GROUP_ID/projects?per_page=100 | jq --arg p "$PREFIX" '.[] | .[$p]' | xargs -L1 git clone

更新后的 Python 3脚本使用 Gitlab 最新的 api 和适当的分页实现了这一点:

import requests
import subprocess, shlex
import os


print('Starting getrepos process..')


key = '12345678901234567890' # your gitlab key
base_url = 'https://your.gitlab.url/api/v4/projects?simple=true&per_page=10&private_token='
url = base_url + key


base_dir = os.getcwd()


while True:
print('\n\nRetrieving from ' + url)
response = requests.get(url, verify = False)
projects = response.json()


for project in projects:
project_name = project['name']
project_path = project['namespace']['full_path']
project_url = project['ssh_url_to_repo']


os.chdir(base_dir)
print('\nProcessing %s...' % project_name)


try:
print('Moving into directory: %s' % project_path)
os.makedirs(project_path, exist_ok = True)
os.chdir(project_path)
cmd = shlex.split('git clone --mirror %s' % project_url)
subprocess.run(cmd)
except Exception as e:
print('Error: ' + e.strerror)


if 'next' not in response.links:
break


url = response.links['next']['url'].replace('127.0.0.1:9999', 'your.gitlab.url')




print('\nDone')

需要 请求库(用于导航到页面链接)。

如果你可以使用一些 shell 技巧,这将克隆所有按组 ID 分组的回购协议(你需要 jq 和并行)

seq 3                                                                           \
| parallel curl -s "'https://[gitlabUrl]/api/v4/projects?page={}&per_page=100&private_token=[privateToken]'
| jq '.[] | .ssh_url_to_repo, .name, .namespace.path'" \
| tr -d '"'                                                                 \
| awk '{ printf "%s ", $0; if (NR % 3 == 0) print " " }'                    \
| parallel --colsep ' ' 'mkdir -p {2} && git clone {1} {3}/{2}'

curljqtr的一个班轮:

for repo in $(curl -s --header "PRIVATE-TOKEN: your_private_token" https://<your-host>/api/v4/groups/<group_id> | jq -r ".projects[].ssh_url_to_repo"); do git clone $repo; done;

对于 Gitlab.com 使用 https://gitlab.com/api/v4/groups/<group_id>

要包含子组 ,添加 include_subgroups=true查询参数,如

https://<your-host>/api/v4/groups/<group_id>?include_subgroups=true

注意: 要使用 http url 进行克隆,请在 jq 中使用 http_url_to_repo而不是 ssh_url_to_repo(感谢@MattVon 提供注释)

另一种在安装了有限软件包的 Windows“ Git Bash”中实现的方法是:

#!/bin/bash
curl -o projects.json https://<GitLabUrl>/api/v4/projects?private_token=<YourToken>
i=0
while : ; do
echo "/$i/namespace/full_path" > jsonpointer
path=$(jsonpointer -f jsonpointer projects.json 2>/dev/null | tr -d '"')
[ -z "$path" ] && break
echo $path
if [ "${path%%/*}" == "<YourProject>" ]; then
[ ! -d "${path#*/}" ] && mkdir -p "${path#*/}"
echo "/$i/ssh_url_to_repo" > jsonpointer
url=$(jsonpointer -f jsonpointer projects.json 2>/dev/null | tr -d '"')
( cd "${path#*/}" ; git clone --mirror "$url" )
fi
let i+=1
done
rm -f projects.json jsonpointer

是的,有可能,这是密码。

先决条件:

Pip install python-gitlab

#!/usr/bin/python3
import os
import sys
import gitlab
import subprocess


glab = gitlab.Gitlab(f'https://{sys.argv[1]}', f'{sys.argv[3]}')
groups = glab.groups.list()
groupname = sys.argv[2]
for group in groups:
if group.name == groupname:
projects = group.projects.list(all=True)


for repo in projects:
command = f'git clone {repo.ssh_url_to_repo}'
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
output, _ = process.communicate()
process.wait()

例如:

  • Create. py 文件(例如 gitlab-downloader.py )
  • 从上面复制粘贴代码
  • 在 Linux 操作系统(或 OSX)上,对脚本文件执行 chmod + x 操作(例如,chmod + x gitlab-downloader.py )
  • 使用3个参数运行它: Gitlab 主机名、组名、个人访问令牌(见 https://gitlab.exmaple.com/profile/personal_access_tokens)

基于 Dmitriy 的答案的一种替代方案——在这种情况下,您将递归地在整个组树中克隆存储库。

#!/usr/bin/python3
import os
import sys
import gitlab
import subprocess


glab = gitlab.Gitlab(f'https://{sys.argv[1]}', f'{sys.argv[3]}')
groups = glab.groups.list()
root = sys.argv[2]


def visit(group):
name = group.name
real_group = glab.groups.get(group.id)


os.mkdir(name)
os.chdir(name)


clone(real_group.projects.list(all=True))


for child in real_group.subgroups.list():
visit(child)


os.chdir("../")


def clone(projects):
for repo in projects:
command = f'git clone {repo.ssh_url_to_repo}'
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
output, _ = process.communicate()
process.wait()


glab = gitlab.Gitlab(f'https://{sys.argv[1]}', f'{sys.argv[3]}')
groups = glab.groups.list()
root = sys.argv[2]


for group in groups:
if group.name == root:
visit(group)

我已经编写了脚本,从 gitlab 中为特定的组提取完整的代码库。

for pag in {1..3} // number of pages projects has span {per page 20 projects so if you have 50 projects loop should be 1..3}
do
curl -s http://gitlink/api/v4/groups/{groupName}/projects?page=$pag > url.txt
grep -o '"ssh_url_to_repo": *"[^"]*"' url.txt | grep -o '"[^"]*"$' | while read -r line ; do
l1=${line%?}
l2=${l1:1}
echo "$l2"
git clone $l2
done
done

作为对@Kosrat D. Ahmad 的回应,我也有同样的问题(对于嵌套的子群,我的问题实际上深入了5个!)

#!/bin/bash
URL="https://mygitlaburl/api/v4"
TOKEN="mytoken"


function check_subgroup {
echo "checking $gid"
if [[ $(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$gid/subgroups/ | jq .[].id -r) != "" ]]; then
for gid in $(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$gid/subgroups/ | jq .[].id -r)
do
check_subgroup
done
else
echo $gid >> top_level
fi
}


> top_level #empty file
> repos #empty file
for gid in $(curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/ | jq .[].id -r)
do
check_subgroup
done
# This is necessary because there will be duplicates if each group has multiple nested groups. I'm sure there's a more elegant way to do this though!
for gid in $(sort top_level | uniq)
do
curl --header "PRIVATE-TOKEN: $TOKEN" $URL/groups/$gid | jq .projects[].http_url_to_repo -r >> repos
done


while read repo; do
git clone $repo
done <repos


rm top_level
rm repos

注意: 如果您愿意,可以使用. ssh _ url _ to _ repo 替换 jq.project [] . Http _ url _ to _ repo

或者去掉 rm,单独查看文件以检查输出等。

无可否认,这将克隆一切,但是您可以随意调整它。

资源: https://docs.gitlab.com/ee/api/groups.html#list-a-groups-subgroups

我为此创建了一个工具: https://github.com/ezbz/gitlabber,您可以使用 globb/regex 表达式来选择您想要克隆的组/子组。

假设您的顶级组名为 MyGroup,并且您希望将其下的所有项目克隆到 ~/GitlabRoot,您可以使用以下命令:

    gitlabber -t <personal access token> -u <gitlab url> -i '/MyGroup**' ~/GitlabRoot

下面是一个 Java 版本,它使用 Gitlab4j和一个访问令牌和 git 命令。

我在 Windows 和 Mac 上运行这个程序,它工作正常。对于 Windows,只需在。执行()

 void doClone() throws Exception {
try (GitLabApi gitLabApi = new GitLabApi("[your-git-host].com/", "[your-access-token]");) {
List<Project> projects = gitLabApi.getGroupApi().getProjects("[your-group-name]");
projects.forEach(p -> {
try {
Runtime.getRuntime().exec("git clone " + p.getSshUrlToRepo(), null, new File("[path-to-folder-to-clone-projects-to]"));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}

修改@Hot Diggity 的回答。

import json
import subprocess, shlex


allProjects     = urlopen("https://gitlab.com/api/v4/projects?private_token=token&membership=true&per_page=1000")
allProjectsDict = json.loads(allProjects.read().decode())
for thisProject in allProjectsDict:
try:
thisProjectURL  = thisProject['ssh_url_to_repo']
path  = thisProject['path_with_namespace'].replace('/', '-')
command     = shlex.split('git clone %s %s' % (thisProjectURL, path))
p  = subprocess.Popen(command)
p_status = p.wait()


except Exception as e:
print("Error on %s: %s" % (thisProjectURL, e.strerror))

对于 powershell (替换和传递来自 gitlab 的私有令牌(或硬编码)) :

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url="https://<gitlab host>/api/v4/groups/<group>/projects?
simple=1&include_subgroups=true&private_token="+$args[0]
$req = Invoke-WebRequest $url | ConvertFrom-Json
foreach( $project in $req ) {
Start-Process git -ArgumentList "clone", $project.ssh_url_to_repo
}

有很多好答案,但这是我的看法,如果你:

  • 想要并行克隆所有的东西
  • 将 ssh 密钥配置为在不输入密码的情况下从服务器克隆
  • 不想创建访问令牌
  • 正在使用类似 git bash 的有限 shell (没有 jq)

因此,使用浏览器访问 https://gitlab.<gitlabserver>/api/v4/groups/<group name>?per_page=1000,下载包含所有项目信息和 将其保存为名为 group.json的文件的 json。

现在只需在同一个目录中运行这个简单的命令:

egrep -o  'git@[^"]+.git' group.json|xargs -n 1 -P 8 git clone

增加 -P 8中的数量以改变并行进程的数量。如果您有超过1000个存储库,那么在 perpage=之后增加数量。

如果 <group name>有空格或重音字符,请注意它必须是 url 编码的。

如果希望自动化下载,验证身份的最简单方法是在 GitLab/GitHub 中生成一个访问令牌,并将其放在 url: https://user:access_toke@mygitlab.net/api/v4/groups/<group name>?per_page=1000中。

使用 curl、 jq 和 tr 以及前面描述的相同方法,但是对于20多个项目:

for repo in $(curl --header "PRIVATE-TOKEN:<Private-Token>" -s "https://<your-host>/api/v4/groups/<group-id>/projects?include_subgroups=true&per_page=100&page=n" | jq '.[].ssh_url_to_repo' | tr -d '"'); do git clone $repo; done;

对于 Gitlab.com,使用 https://gitlab.com/api/v4/groups/[group-id]/projects

只需要迭代更改页码即可。

Dinesh Balasubramanian 响应的一个线性 python3版本。

我这样做只是因为缺少 jq,只有 python3(请求)

import requests,os; [os.system('git clone {[http_url_to_repo]}'.format(p)) for p in requests.get('https://<<REPO_URL>>/api/v4/groups/<<GROUP_ID>>',headers={'PRIVATE-TOKEN':'<<YOUR_PRIVATE_TOKEN>>'},verify=False).json()['projects']]

替换 < < REPO _ URL > > 、 < < GROUP _ ID > > 和 < 您的私人物品 _ TOKEN > >

这是@ruben-lohaus post 中 oneliner 的一个改进版本。

  • 它将工作多达100回购在集团。
  • 将克隆组中的每个存储库,包括路径。

要求:

  • Grep
  • JQ
  • 卷发

GITLAB_URL="https://gitlab.mydomain.local/api/v4/groups/1141/projects?include_subgroups=true&per_page=100&page=0"


GITLAB_TOKEN="ABCDEFABCDef_5n"


REPOS=$(curl --header "PRIVATE-TOKEN:${GITLAB_TOKEN}" -s "${GITLAB_URL}" | jq -r '.[].ssh_url_to_repo')


for repo in $(echo -e "$REPOS")
do git clone $repo $(echo $repo | grep -oP '(?<=:).*(?=.git$)')
done

基于 这个答案,用个人访问令牌代替 SSH 进行 git 克隆。
一个班轮与 curljqtr

没有分组:

for repo in $(curl -s --header "PRIVATE-TOKEN: <private_token>" https://<your-host>/api/v4/groups/<group-name> | jq ".projects[]".http_url_to_repo | tr -d '"' | cut -c 9-); do git clone https://token:<private_token>@$repo; done;

包括小组:

for repo in $(curl -s --header "PRIVATE-TOKEN: <private_token>" "https://<your-host>/api/v4/groups/<group-name>/projects?include_subgroups=true&per_page=1000" | jq ".[]".http_url_to_repo | tr -d '"' | cut -c 9-); do git clone https://token:<private_token>@$repo; done;

请注意,旋度的 private_token必须具有 API权限。git cloneprivate_token必须至少拥有 read_repository权限。它可以是相同的令牌(如果它有 API权限) ,但也可以是2个不同的令牌

我的理解是,所有的答案只允许你克隆回购,但没有问题,董事会,其他设置等。如果我说错了,请纠正我。

我觉得如果我想备份所有的数据从多个项目,目的是不仅包括回购,但也包括其他数据,这可能是重要的回购。

自托管 Gitlab 实例可以在官方支持下实现这一点,请参阅 备份和恢复 GitLab

如果你有远远超过20个项目在该组,你必须处理分页 https://docs.gitlab.com/ee/api/#pagination。也就是说,您必须执行多个请求才能克隆所有项目。最具挑战性的部分是在小组中获得完整的项目列表。下面是如何在 bash shell 中使用 curljq进行操作:

for ((i = 1; i <= <NUMBER_OF_ITERATIONS>; i++)); do curl -s --header "PRIVATE-TOKEN: <YOUR_TOKEN>" "https://<YOUR_URL>/api/v4/groups/<YOUR_GROUP_ID>/projects?per_page=100&page=${i}" | jq -r ".[].ssh_url_to_repo"; done | tee log

for循环中的迭代次数可以从单独请求中的 X-Total-Pages响应头中获得,请参见 在 Gitlab 应用程序编程接口中的分页只返回每页最多100个

获取项目列表后,您可以用以下方法克隆项目:

for i in `cat log`; do git clone $i; done

不需要编写代码,只要聪明就好

  1. 在 chrome 中,我们有一个扩展,可以抓取所有 URL 的“ Link Klipper”

  2. 提取所有的网址到一个 Excel 文件只是过滤他们在 Excel

  3. 创建 .sh文件

    #!/bin/bash
    git clone https:(url) (command)
    
  4. 运行此脚本,完成所有存储库的将被克隆到您的本地机器上

我有点不高兴,这拉在 archivedempty回购的,我承认不是每个人都有问题。所以我根据公认的答案做了下面这个怪物。

for repo in $(curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "https://gitlab.spokedev.xyz/api/v4/groups/238?include_subgroups=true" | jq '.projects[] | select(.archived == false) | select(.empty_repo == false) | .http_url_to_repo' | sed s"-https://gitlab-https://oauth2:\${GITLAB_TOKEN}@gitlab-g"); do
echo "git clone $repo"
done | bash

这是从最上面的答案派生出来的,以给予充分的信任; 但它只是演示了基于属性的选择(由于某些原因 = = = 不起作用)。我也有这个使用 HTTPS 克隆,因为我们设置的密码对我们的 SSH 密钥,不希望他们在密钥链,或类型的密码很多次。

我正在努力解决这里发布的脚本的问题,所以我使用 PostMan 的 API 调用、 JSON Query 和一个哑 bash 脚本创建了一个简化的混合版本。以下是防止其他人碰到这种情况的步骤。

  1. 给你群名。由于某种原因,我的组 ID 与组页面上显示的内容不匹配。通过点击这里的 api: https://gitlab.com/api/v4/groups来抓住它
  2. 使用 Postman 点击 API 列出你的项目 URL: < a href = “ https://gitlab.com/API/v4/groups/PROJECT _ ID/Projects? per _ page = 100 & amp; include _ subgroups = true”rel = “ nofollow noReferrer”> https://gitlab.com/API/v4/groups/project_id/projects?per_page=100&include_subgroups=true 将 Auth 设置为使用 API 密钥,其中密钥为“ PRIVATE-TOKEN”,值为您的私有 API 密钥
  3. 复制结果并把它们放到: < a href = “ https://www.jsonquerytool.com/”rel = “ nofollow norefrer”> https://www.jsonquerytool.com/ 将转换切换到 JSONata。将查询更改为“ $. http _ url _ to _ repo”(如果使用 SSH,则为 SSH _ url _ to _ repo)
  4. 您现在应该有一个要克隆的 git url 的 JSON 数组。更改格式以匹配 Bash 数组符号(将[]更改为()并删除逗号)。
  5. 将 Bash 数组拖放到下面脚本的 repos 变量中。
repos=(
""
)
for repo in ${repos[@]}; do git clone $repo
done
  1. 将您的脚本保存在您希望检出回购协议的文件夹中。
  2. 运行 bash {yourscriptname}.sh
  3. 这样就可以了,你现在应该有一个目录,为了备份的目的,你所有的回购协议都已经检查过了。