【问题标题】:How to clone all projects of a group at once in GitLab?如何在 GitLab 中一次克隆一个组的所有项目?
【发布时间】:2015-05-19 21:40:33
【问题描述】:

在我的 GitLab 存储库中,我有一个包含 20 个项目的组。我想一次克隆所有项目。这可能吗?

【问题讨论】:

    标签: git gitlab


    【解决方案1】:
    推荐的答案 GitLab

    不是真的,除非:

    • 您有一个第 21 个项目,将其他 20 个项目引用为 submodules
      (在这种情况下,一个克隆后跟一个git submodule update --init 就足以克隆并签出所有 20 个项目)

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


    自 2015 年以来,Jay Gabez 提到了 in the comments(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
    

    【讨论】:

    • ghorg 是一个小 cli,将为您完成此操作
    • @JayGabez 谢谢。我已将您的评论包含在答案中以提高知名度。
    • 如果这是您整个团队经常使用的功能,我建议自动创建集合存储库(根据第一个建议)。这将使一切保持良好和一致,并避免让您的开发人员使用除了他们选择的 vanilla git 客户端之外的其他工具。通过 API 和 webhook 实现也相当简单。当然,要小心意外的反馈循环......
    【解决方案2】:

    以下是 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))
    

    【讨论】:

    • 由于未知的编码问题,我在反序列化 json 时遇到了一些问题,在这种情况下,通过正则表达式解析的修改有所帮助:urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+.git', allProjects.read().decode("latin-1"))
    • 脚本运行良好。我有两个问题:stackoverflow.com/a/31601343/2777965 我不得不使用 https:// 而不是 http
    • 此脚本使用旧的 api 版本,当前 url 为 https://[yourServer:port]/api/v4/projects?private_token=[yourPrivateTokenFromUserProfile]&per_page=100
    • 如何指定子组?
    【解决方案3】:

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

    mr update
    

    为了将所有gitlab项目注册到mr,这里有一个小python脚本。它需要安装包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"])
    

    【讨论】:

    【解决方案4】:

    您可以在此处参考此 ruby​​ 脚本: 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

    【讨论】:

      【解决方案5】:

      我为此构建了一个脚本(需要 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

      【讨论】:

      • 如何下载组中的子组(嵌套组)??
      • 你好@KosratD.Ahmad!您可能想为此探索 GitLab API。这是可能的,但我没有开发该功能的用例。
      • @KosratD.Ahmad - 看来我不能从另一个答案@你 - 看看我的回答和评论(如果你仍然活跃)
      • v3 api 已弃用,请改用 v4:{"error":"API V3 不再受支持。请改用 API V4。"}
      【解决方案6】:

      这是另一个克隆组中所有存储库的 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
      

      【讨论】:

      • 这对我来说非常适合 Windows 7 上的 git bash shell。下载的 jq-win64.exe 文件必须重命名为 jq.exe 并放在搜索路径中的文件夹中(对我来说是 ~/bin/jq.exe)。在 gitlab 中,我必须生成一个个人访问令牌,并确保将其存储在安全的地方以备将来使用。
      【解决方案7】:

      一个更新的 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')
      

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

      【讨论】:

      • 不是下载实际工程。只需在项目中创建一些垃圾文件夹,如 app1.git、app2.git
      • 自从发表这篇文章后,他们的 API 可能已经发生了变化。如果您发现其中的差异,请随时提供修改。
      【解决方案8】:

      如果你对一些 shell 巫术没问题,这将克隆所有按 group-id 分组的 repos(你需要 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}'
      

      【讨论】:

        【解决方案9】:

        一个带curljqtr的班轮:

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

        对于 Gitlab.com 使用 https://gitlab.com/api/v4/groups/&lt;group_id&gt;

        要包括子组添加include_subgroups=true查询参数喜欢

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

        【讨论】:

        • 又好又简单!迄今为止最好的一次性答案。值得一提的是,这仅适用于bashcurl 并且必须安装jq
        • 这只有在知道组 id 并且没有任何子组的情况下才有效。
        • 好的,可以使用include_subgroups=true获取所有项目。
        • 我必须在 jq 部分添加引号。 for repo in $(curl "https://&lt;your-host&gt;/api/v4/groups/&lt;group_id&gt;?private_token=&lt;your_private_token&gt;" | 'jq .projects[].ssh_url_to_repo' | tr -d '"'); do git clone $repo; done;
        • 这只会给出组文件夹中的项目。如何获取子组(子文件夹)中的项目?
        【解决方案10】:

        另一种使用安装了有限软件包的 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
        

        【讨论】:

          【解决方案11】:

          是的,这是可能的,这是代码。

          先决条件:

          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()
          

          示例:

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

          【讨论】:

            【解决方案12】:

            基于 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)
            

            【讨论】:

            • 工作。前几天克隆了很多组,没有任何错误。
            【解决方案13】:

            我已经编写了脚本来从 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
            

            【讨论】:

              【解决方案14】:

              回复@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
              

              注意:我使用 jq .projects[]。http_url_to_repo 如果您愿意,可以将其替换为 .ssh_url_to_repo。

              或者剥离 rm 并单独查看文件以检查输出等。

              诚然,这将克隆所有内容,但您可以随意调整它。

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

              【讨论】:

              • @Kosrat D. Ahmad 我知道已经晚了 - 知道你想出什么解决方案会很有趣。
              【解决方案15】:

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

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

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

              【讨论】:

                【解决方案16】:

                这是一个适用于我的 Java 版本,它使用带有访问令牌和 git 命令的 gitlab4j

                我在 Windows 和 Mac 上运行了它,它可以工作。对于 Windows,只需在 .exec() 中的 'git clone' 之前添加 'cmd /c'

                 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();
                            }
                        });
                    }
                }
                

                【讨论】:

                  【解决方案17】:

                  修改了@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))
                  

                  【讨论】:

                    【解决方案18】:

                    对于 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
                    }
                    

                    【讨论】:

                      【解决方案19】:

                      很多很好的答案,但这是我的看法。在以下情况下使用它:

                      • 想要并行克隆所有内容
                      • 将您的 ssh 密钥配置为无需输入密码即可从服务器克隆
                      • 不想费心创建访问令牌
                      • 正在使用像 git bash 这样的受限 shell

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

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

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

                      增加-P 8中的数字以更改并行进程数。

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

                      如果你想自动下载,最简单的认证方法是在 GitLab/GitHub 中生成一个访问令牌,并将其放入 url:https://user:access_toke@mygitlab.net/api/v4/groups/&lt;group name&gt;?per_page=1000

                      【讨论】:

                      • 我喜欢的方法,但我更喜欢jq。但是,此解决方案默认下载不超过 20 个项目。指定per_page=100page 查询参数以检索更多。
                      • 这种方法使导出一组项目变得简单。如果您有子组,即父/子,&lt;group name&gt; 将是 url 编码值,即parent%2Fchild
                      【解决方案20】:

                      使用 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

                      只需要迭代改变页码。

                      【讨论】:

                        【解决方案21】:

                        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']]
                        

                        替换 >、> 和 >

                        【讨论】:

                          猜你喜欢
                          • 2020-09-06
                          • 2016-08-25
                          • 2011-01-30
                          • 2021-06-29
                          • 1970-01-01
                          • 2013-12-17
                          • 1970-01-01
                          • 2013-11-27
                          • 2017-12-19
                          相关资源
                          最近更新 更多