【问题标题】:How to permanently add upstream location to git repo?如何将上游位置永久添加到 git repo?
【发布时间】:2014-10-05 15:03:18
【问题描述】:

git 的一个烦恼是我必须为我从一些上游 repo(例如 Github forks)分叉的 repo 制作的每个克隆使用git remote add upstream URL。理想情况下,我应该能够将上游位置存储在分叉回购本身中,以便所有克隆自动设置它。有没有办法使用 git 来完成这个?

【问题讨论】:

  • 我不确定我是否理解您的问题。正如 Andrew 所指出的,默认情况下,克隆的 repo 知道(在名称“origin”下)它被克隆的远程。您希望该名称改为“上游”(在这种情况下,您应该查看 Andrew 的答案),还是尝试在克隆时添加第二个遥控器?
  • 添加第二个远程指向原始存储库,该原始存储库是从中分叉的。我已经在问题中澄清了这一点。感谢您指出歧义!

标签: git


【解决方案1】:

就 Git 本身而言,原始存储库(即您从中分叉的存储库)与您的分叉克隆之间没有任何联系;后者中不包含有关前者 URL 的信息。因此,无论哪种方式,您都必须将原始存储库添加为克隆之后克隆的远程。

为了稍微自动化一些事情并避免每次都输入 URL,您可以为您派生的每个项目定义一个别名:

git config alias.remaddfoo "remote add upstream <URL-of-original-project-foo>"

克隆你的 fork 后,你必须在新克隆中 cd 并记住调用相应的别名。

更进一步的自动化将涉及在git clone 周围编写某种包装器,它会在克隆内部自动cd 并运行git remote add...,但正确解析git clone 的参数可能有点太复杂了。

【讨论】:

    【解决方案2】:

    正如其他答案所述,git 目前没有将 repos 链接在一起的内置功能。

    因此,我编写了一个名为 clone 的小型 Python 脚本,它使用 BeatifulSoup 4 解析 BitBucket 和 GitHub 的上游存储库,并将其添加为名为 upstream 的远程。这适用于 git 和 Mercurial。它是hosted on GitHub,但为了完成,我在这个答案中包含了完整的脚本:

    #! /usr/bin/env python3
    description='''
    A wrapper for repo cloning commands for various DVCS.
    Automatically adds the upstream URL when cloning a forked repo from
    popular DVCS web hosts.
    Currently supports:
     (DVCS: git, Mercurial)
     (hosts: GitHub, Bitbucket)
    '''
    # Created by Jesse Johnson a.k.a. holocronweaver (2014-10-08).
    import argparse
    import re
    import subprocess
    import urllib.request
    
    from bs4 import BeautifulSoup
    
    def find(regex, string, errorMessage):
        '''Return value at regex, or else print error message and exit program.'''
        m = re.search(regex, string)
        if (m):
            return m.group(1)
        else:
            print('Error:', errorMessage)
            exit()
    
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument('origin', metavar='O', type=str,
                        help='the SSH URL of origin repo, optionally'
                        'followed by its destination folder')
    args = parser.parse_args()
    
    # Parse destination.
    splitArgs = re.split('\s+', args.origin)
    if len(splitArgs) > 1:
        origin = splitArgs[0]
        destination = splitArgs[1]
    else:
        origin = args.origin
        destination = find('@.*\.\w+[:|/].*/(.*)[.git]?$', origin,
                                'Error: Could not parse destination folder from origin URL.')
        destination = re.sub('\.git', '', destination)
    print('destination folder:', destination)
    
    # Unfortunately HTTPS URLs do not contain enough info to clarify which
    # DVCS is being used, so SSH is easiest to support.
    vcs = find('^[ssh://]?(.*)@', origin,
               'URL does not contain SSH user (e.g., git@ or hg@).')
    print('version control system:', vcs)
    
    domain = find('@(.*\.\w+)[:|/]', origin,
                  'Error: Could not parse domain from origin URL.')
    print('domain:', domain)
    
    path = find('@.*\.\w+([:|/].*)[.git]?$', origin,
             'Error: Could not parse repo path from origin URL.')
    path = re.sub(':', '/', path)
    print('repo path:', path)
    
    homepage = 'https://' + domain + path
    print(homepage)
    
    data = urllib.request.urlopen(homepage).read()
    soup = BeautifulSoup(data)
    
    # Version control system specifics.
    if ('git@' in origin):
        ext = '.git'
        clone = 'git clone %s %s'
        setUpstream = 'git remote add upstream %s'
    elif ('hg@' in origin):
        ext = ''
        clone = 'hg clone %s %s'
        setUpstream = 'echo "upstream = %s \n" >> .hg/hgrc'
    else:
        print('Error: Version control system not supported.')
        exit()
    
    upstream = None
    if ('github.com' in origin):
        element = soup.find('span', class_='fork-flag')
        if element:
            upstreamBase = element.span.a['href']
            upstream = 'https://github.com' + upstreamBase + ext
    elif ('bitbucket.org' in origin):
        element = soup.find('a', class_='fork-of')
        if element:
            upstreamBase = element['href']
            upstream = 'https://bitbucket.org' + upstreamBase + ext
    else:
        print('Warning: Web host not supported.')
        print('Warning: Continuing to clone without adding upstream repo.')
    
    print(upstream)
    
    subprocess.Popen(clone % (origin, destination), shell=True).wait()
    if upstream:
        subprocess.Popen(setUpstream % upstream, cwd=destination, shell=True).wait()
    

    【讨论】:

      【解决方案3】:

      默认情况下git clone 调用您的远程“源”。如果您想将其称为其他名称,请使用

      git clone -o upstream <path_to_repo>
      

      Git Clone

      --origin <name>
      -o <name>
      Instead of using the remote name origin to keep track of the upstream repository, use <name>.
      

      编辑:对于您需要跟踪遥控器的遥控器的情况......我从来没有找到这样做的好方法。您可以围绕 git clone 编写一个包装器,但必须为每个存储库进行硬编码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-25
        • 2018-01-04
        • 2011-03-25
        相关资源
        最近更新 更多