将您的项目从 GitHub 导入极狐GitLab

您可以导入您的 GitHub 仓库:

  • 从 GitHub.com 或 GitHub Enterprise。
  • 到 JiHuLab.com 或私有化部署的极狐GitLab 实例。

此过程不会将任何类型的组或组织从 GitHub 迁移或导入到极狐GitLab。

命名空间是极狐GitLab 中的用户或群组。您可以在 rails 控制台中使用批量操作将项目移动到不同的命名空间。

如果要导入到私有化部署的极狐GitLab 实例,则可以改用 GitHub Rake 任务,允许您在没有 Sidekiq worker 的约束的情况下导入项目。

如果您从 GitHub Enterprise 导入到私有化部署的极狐 GitLab 实例:

  • 您必须首先启用 GitHub 集成
  • 如果您从 GitHub.com 导入到极狐GitLab 私有化部署实例,使用 Import API。
  • 如果极狐GitLab 位于 HTTP/HTTPS 代理之后,您必须使用 github.comapi.github.com 来解析主机名。

如果您从 GitHub.com 导入到私有化部署版的极狐 GitLab 实例:

  • 不需要设置 GitHub 集成。
  • 您可以使用 Import API。

当导入项目时:

  • 如果在极狐GitLab 数据库中找不到项目中引用的用户,则将项目创建者设置为作者和指派人。项目创建者通常是启动导入过程的用户,并添加关于提到原始 GitHub 作者的议题的备注。
  • 如果新的命名空间(或群组)不存在,则导入器会创建它们,或者,如果使用了命名空间,则将仓库导入到启动导入过程的用户的命名空间下。命名空间或仓库名称也可以使用适当的权限进行编辑。
  • 导入器还导入与开放拉取请求相关的派生项目上的分支。这些分支是使用类似于 GH-SHA-username/pull-request-number/fork-name/branch 的命名方案导入的。与 GitHub 仓库的分支相比,可能会导致分支的差异。

先决条件

在导入议题和拉取请求时,导入器会尝试在极狐GitLab 实例的数据库中查找其 GitHub 作者和指派人。拉取请求在极狐GitLab 中称为 合并请求

要使此关联成功,仓库中的每个 GitHub 作者和指派人必须在导入之前满足以下条件之一:

  • 之前已使用 GitHub icon 登录极狐GitLab 帐户。
  • 拥有一个 GitHub 帐户,其面向公众的电子邮件地址与其极狐GitLab 帐户的电子邮件地址相匹配。

使用 GitHub 帐户的极狐GitLab 内容导入需要填充 GitHub 面向公众的电子邮件地址,所有评论和贡献都正确映射到极狐GitLab 中的同一用户。GitHub Enterprise 不需要填充此字段,因此您可能必须将其添加到现有帐户中。

将您的 GitHub 存储库导入极狐GitLab

使用 GitHub 集成

在开始之前,请确保您要映射到极狐GitLab 用户的任何 GitHub 用户具有:

  • 使用 GitHub 图标登录的极狐GitLab 帐户 - 或 -
  • 一个极狐GitLab 帐户,其电子邮件地址与 GitHub 用户个人资料中的公开可见的电子邮件地址匹配

用户匹配尝试按该顺序发生,如果用户未通过任一方式识别,则该动态与执行导入的用户帐户相关联。

note如果您使用的是极狐GitLab 自助管理实例或者如果您是从 GitHub Enterprise 导入,则此过程要求您已配置 GitHub 集成。
  1. 在顶部导航栏中,单击 + 并选择 新建项目
  2. 选择 导入项目 选项卡,然后选择 GitHub
  3. 选择第一个按钮以 列出您的 GitHub 仓库。您将被重定向到 GitHub 上的页面以授权极狐GitLab 应用程序。
  4. 点击 授权 GitlabHQ。您将被重定向回极狐GitLab 导入页面,并列出您的所有 GitHub 仓库。
  5. 继续选择要导入的仓库

使用 GitHub 令牌

note不建议使用个人访问令牌导入项目。如果您是 SaaS 用户,您可以使用个人访问令牌从 GitHub 导入您的项目,但此方法无法将所有用户动态(例如议题和拉取请求)与匹配的极狐GitLab 用户相关联。如果您是极狐GitLab 自助管理实例的管理员,或者您是从 GitHub Enterprise 导入,则不能使用个人访问令牌。推荐所有用户使用上方的 GitHub 集成方法。在工作原理部分阅读更多内容。

如果您没有使用 GitHub 集成,您仍然可以使用 GitHub 执行授权,授予极狐GitLab 访问您仓库的权限:

  1. 前往 https://github.com/settings/tokens/new
  2. 输入令牌描述。
  3. 选择仓库范围。
  4. 点击 生成令牌
  5. 复制令牌哈希。
  6. 返回极狐GitLab 并将令牌提供给 GitHub 导入器。
  7. 点击 列出您的 GitHub 仓库 按钮并等待极狐GitLab 读取您的仓库信息。完成后,您将进入导入器页面,选择要导入的仓库。

要在执行上述这些步骤后,在导入中使用更新的个人访问令牌,请注销您的极狐GitLab 帐户并重新登录,或在 GitHub 中撤销旧的个人访问令牌。

选择要导入的其他项目

引入于极狐GitLab 15.5。

为了尽可能快地导入,默认情况下不会从 GitHub 导入以下项目:

  • 议题和拉取请求事件。例如,开放的关闭的重命名的 以及 打标记的未打标记的 事件。
  • 所有评论。在定期导入大型仓库时,由于 GitHub API 的限制,可能会跳过一些评论。
  • 来自仓库评论、发布公告、议题描述和拉取请求描述的 Markdown 附件。可能包括图像、文本或二进制附件。如果未导入,从 GitHub 中删除附件后,Markdown 中的附件链接将失效。

您可以选择导入这些项目,但这可能会显着增加导入时间。要导入这些项目,请在 UI 中选择适当的字段:

  • 导入议题和拉取请求事件
  • 使用替代注释导入方法
  • 导入 Markdown 附件

选择要导入的仓库

在您授权访问您的 GitHub 仓库后,您将被重定向到 GitHub 导入器页面并列出您的 GitHub 仓库。

  1. 默认情况下,建议的仓库命名空间与 GitHub 中存在的名称匹配,但根据您的权限,您可以选择在继续导入其中任何名称之前编辑这些名称。
  2. 选择任意数量的仓库旁边的 导入 按钮,或选择 导入所有仓库。此外,您可以按名称过滤项目。如果应用过滤器,导入所有仓库 仅导入匹配的仓库。
  3. 状态 列显示每个仓库的导入状态。您可以选择让页面保持打开状态,它会实时更新,也可以稍后返回。
  4. 导入仓库后,单击其极狐GitLab 路径,打开其极狐GitLab URL。

GitHub importer page

镜像仓库并共享流水线状态

根据您的极狐GitLab 订阅级别,可以设置仓库镜像,使您导入的仓库与其 GitHub 副本保持同步。

此外,您可以将极狐GitLab 配置为使用 GitHub 项目集成,将流水线状态更新发送回 GitHub。 如果您使用外部仓库的 CI/CD 导入您的项目,那么上述两个事项都会自动配置。

note镜像不会从您的 GitHub 项目同步任何新的或更新的拉取请求。

提高私有化部署实例上的导入速度

note此流程需要 GitLab 服务器上的管理员角色。

对于大型项目,导入所有数据可能需要一段时间。为了减少必要的时间,您可以增加处理以下队列的 Sidekiq workers 的数量:

  • github_importer
  • github_importer_advance_stage

为获得最佳体验,建议至少有 4 个 Sidekiq 进程(每个进程运行的线程数与 CPU 内核数相同)处理这些队列。还建议这些进程在单独的服务器上运行。对于具有 8 核的 4 个服务器,这意味着您最多可以并行导入 32 个对象(例如,议题)。

可以通过增加存储 Git 仓库(用于您的极狐GitLab 实例)的磁盘的网络吞吐量、CPU 容量和磁盘性能(例如,通过使用高性能 SSD),来减少克隆仓库所花费的时间。 增加 Sidekiq workers 的数量不会减少克隆仓库所花费的时间。

导入的数据

导入项目的以下数据:

  • 仓库描述
  • Git 仓库数据
  • 议题
  • 拉取请求
  • Wiki 页面
  • 里程碑
  • 标记
  • 发行说明描述
  • 附件,在 github_importer_attachments_import 功能标志后面默认禁用所有附件导入。从 15.5 版本开始,可以作为附加项导入,功能标志已被删除。支持以下对象:
    • 发行说明(引入于 15.4 版本)
    • 评论和备注(引入于 15.5 版本)
    • 议题的描述(引入于 15.5 版本)
    • 合并请求的描述(引入于 15.5 版本)
  • 拉取请求审核评论
  • 拉取请求审核
  • 拉取请求的审核者(引入于 15.6 版本)
  • 拉取请求 “merged by” 信息
  • 普通议题和拉取请求评论
  • Git 大文件存储 (LFS) 对象
  • 讨论中的拉取请求评论回复(14.5 及以上版本)
  • 差异注释建议 (14.7 及以上版本,功能标志为 github_importer_use_diff_note_with_suggestions,默认启用)
  • 议题事件和拉取请求事件(引入于 15.4 版本,功能标志为 github_importer_issue_events_import,默认禁用)

保留对拉取请求和议题的引用,并且每个导入的仓库都保持可见性级别,除非可见性级别受到限制,在这种情况下,使用默认的项目可见性。

导入注释和差异注释的替代方法

当 GitHub Importer 在超大型项目上运行时,由于 GitHub API issues_commentspull_requests_comments 端点限制,并非所有注释和差异注释都可以导入。 由于来自 GitHub API 的以下错误,并非所有页面都可以获取:In order to keep the API fast for everyone, pagination is limited for this resource. Check the rel=last link relation in the Link response header to see how far back you can traverse.

在功能标志后面提供了另一种导入注释和差异注释的方法。

不要使用 issues_commentspull_requests_comments,而是使用单独的资源 issue_commentspull_request_comments 一次从一个对象中提取注释。 这样做可以保留任何丢失的注释,但是它增加了执行导入所需的网络请求数量,这意味着它的执行需要更长的时间。

要使用导入注释的替代方式,必须在要导入的组项目上启用 github_importer_single_endpoint_notes_import 功能标志。

启动 Rails 控制台。

group = Group.find_by_full_path('my/group/fullpath')

# Enable
Feature.enable(:github_importer_single_endpoint_notes_import, group)

# Disable
Feature.disable(:github_importer_single_endpoint_notes_import, group)

减少每页的 GitHub API 请求对象

对于从大型仓库导入的项目,某些 GitHub API 端点可能会返回 500 或 502 错误。 为了减少出现此类错误的机会,您可以在导入数据的群组项目中启用功能标志 github_importer_lower_per_page_limit。这会将页大小从 100 减少到 50。

要启用功能标志,启动一个 Rails 控制台,并运行以下 enable 命令:

group = Group.find_by_full_path('my/group/fullpath')

# Enable
Feature.enable(:github_importer_lower_per_page_limit, group)

要禁用该功能,请运行以下命令:

# Disable
Feature.disable(:github_importer_lower_per_page_limit, group)

从内部网络上的 GitHub Enterprise 导入

如果您的 GitHub Enterprise 实例位于 Internet 无法访问的内部网络上,您可以使用反向代理来允许 JiHuLab.com 访问该实例。

代理需要:

  • 将请求转发到 GitHub Enterprise 实例。
  • 将所有出现的内部主机名转换为公共代理主机名:
    • API 返回体
    • API 返回的 Link header

GitHub API 使用 Link header 进行分页。

配置代理后,通过发出 API 请求对其进行测试。下面是一些用于测试 API 的命令示例:

curl --header "Authorization: Bearer <YOUR-TOKEN>" "https://{PROXY_HOSTNAME}/user"

### URLs in the response body should use the proxy hostname

{
  "login": "example_username",
  "id": 1,
  "url": "https://{PROXY_HOSTNAME}/users/example_username",
  "html_url": "https://{PROXY_HOSTNAME}/example_username",
  "followers_url": "https://{PROXY_HOSTNAME}/api/v3/users/example_username/followers",
  ...
  "created_at": "2014-02-11T17:03:25Z",
  "updated_at": "2022-10-18T14:36:27Z"
}
curl --head --header "Authorization: Bearer <YOUR-TOKEN>" "https://{PROXY_DOMAIN}/api/v3/repos/{repository_path}/pulls?states=all&sort=created&direction=asc"

### Link header should use the proxy hostname

HTTP/1.1 200 OK
Date: Tue, 18 Oct 2022 21:42:55 GMT
Server: GitHub.com
Content-Type: application/json; charset=utf-8
Cache-Control: private, max-age=60, s-maxage=60
...
X-OAuth-Scopes: repo
X-Accepted-OAuth-Scopes:
github-authentication-token-expiration: 2022-11-22 18:13:46 UTC
X-GitHub-Media-Type: github.v3; format=json
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4997
X-RateLimit-Reset: 1666132381
X-RateLimit-Used: 3
X-RateLimit-Resource: core
Link: <https://{PROXY_DOMAIN}/api/v3/repositories/1/pulls?page=2>; rel="next", <https://{PROXY_DOMAIN}/api/v3/repositories/1/pulls?page=11>; rel="last"

还要测试使用代理克隆仓库不会失败:

git clone -c http.extraHeader="Authorization: basic <base64 encode YOUR-TOKEN>" --mirror https://{PROXY_DOMAIN}/{REPOSITORY_PATH}.git

示例反向代理配置

以下配置是关于如何将 Apache HTTP Server 配置为反向代理的示例。

caution为简单起见,该代码段没有配置来加密客户端和代理之间的连接。但是,出于安全原因,您应该包括该配置。请参阅 Apache TLS/SSL 示例配置
# Required modules
LoadModule filter_module lib/httpd/modules/mod_filter.so
LoadModule reflector_module lib/httpd/modules/mod_reflector.so
LoadModule substitute_module lib/httpd/modules/mod_substitute.so
LoadModule deflate_module lib/httpd/modules/mod_deflate.so
LoadModule headers_module lib/httpd/modules/mod_headers.so
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_connect_module lib/httpd/modules/mod_proxy_connect.so
LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
LoadModule ssl_module lib/httpd/modules/mod_ssl.so

<VirtualHost GITHUB_ENTERPRISE_HOSTNAME:80>
  ServerName GITHUB_ENTERPRISE_HOSTNAME

  # Enables reverse-proxy configuration with SSL support
  SSLProxyEngine On
  ProxyPass "/" "https://GITHUB_ENTERPRISE_HOSTNAME/"
  ProxyPassReverse "/" "https://GITHUB_ENTERPRISE_HOSTNAME/"

  # Replaces occurrences of the local GitHub Enterprise URL with the Proxy URL
  # GitHub Enterprise compresses the responses, the filters INFLATE and DEFLATE needs to be used to
  # decompress and compress the response back
  AddOutputFilterByType INFLATE;SUBSTITUTE;DEFLATE application/json
  Substitute "s|https://GITHUB_ENTERPRISE_HOSTNAME|https://PROXY_HOSTNAME|ni"
  SubstituteMaxLineLength 50M

  # GitHub API uses the response header "Link" for the API pagination
  # For example:
  #   <https://example.com/api/v3/repositories/1/issues?page=2>; rel="next", <https://example.com/api/v3/repositories/1/issues?page=3>; rel="last"
  # The directive below replaces all occurrences of the GitHub Enterprise URL with the Proxy URL if the
  # response header Link is present
  Header edit* Link "https://GITHUB_ENTERPRISE_HOSTNAME" "https://PROXY_HOSTNAME"
</VirtualHost>

故障排除

手动继续之前失败的导入过程

在某些情况下,GitHub 导入过程可能无法导入仓库。这会导致极狐GitLab 中止项目导入过程并要求手动导入仓库。管理员可以为失败的导入过程手动导入仓库:

  1. 打开 Rails 控制台。
  2. 在控制台中运行以下一系列命令:

    project_id = <PROJECT_ID>
    github_access_token =  <GITHUB_ACCESS_TOKEN>
    github_repository_path = '<GROUP>/<REPOSITORY>'
    
    github_repository_url = "https://#{github_access_token}@github.com/#{github_repository_path}.git"
    
    # Find project by ID
    project = Project.find(project_id)
    # Set import URL and credentials
    project.import_url = github_repository_url
    project.import_type = 'github'
    project.import_source = github_repository_path
    project.save!
    # Create an import state if the project was created manually and not from a failed import
    project.create_import_state if project.import_state.blank?
    # Set state to start
    project.import_state.force_start
    # Trigger import from second step
    Gitlab::GithubImport::Stage::ImportRepositoryWorker.perform_async(project.id)