使用文件导出迁移项目

任何私有化部署实例或 SaaS 上的现有项目都可以导出到文件中,然后导入到新的极狐GitLab 实例中。您还可以:

设置项目导入/导出

在您可以导入或导出项目及其数据之前,您必须对其进行设置。

  1. 在左侧边栏中,选择 设置 > 通用
  2. 展开 可见性和访问控制
  3. 滚动到 导入来源
  4. 启用所需的 导入来源

导出项目及其数据

在您可以导入项目之前,您必须将其导出。

先决条件:

  • 查看导出的数据的列表,并非所有数据都导出。
  • 您必须至少具有项目的维护者角色。

要导出项目及其数据,请执行以下步骤:

  1. 在顶部栏上,选择 菜单 > 项目 并找到您的项目。
  2. 在左侧边栏,选择 设置 > 通用
  3. 展开 高级
  4. 选择 导出项目
  5. 导出生成后,您应该会收到一封电子邮件,其中包含下载文件的链接。
  6. 或者,您可以返回项目设置,并从那里下载文件或生成新的导出。文件可用后,页面显示 下载导出 按钮。

导出是在您配置的 shared_path(一个临时共享目录)中生成的,然后移动到您配置的 uploads_directory。每 24 小时,worker 会删除这些导出文件。

导出的数据

导出以下数据:

  • 项目和 wiki 仓库
  • 项目上传文件
  • 项目配置,不包括集成
  • 议题
    • 议题评论
    • 议题资源状态事件(引入于 15.4 版本)
    • 议题资源里程碑事件(引入于 15.4 版本)
  • 合并请求
    • 合并请求差异
    • 合并请求评论
    • 合并请求资源状态事件(引入于 15.4 版本)
  • 标记
  • 里程碑
  • 代码片段
  • 时间跟踪和其他项目实体
  • 设计管理文件和数据
  • LFS 对象
  • 议题看板
  • 流水线历史
  • 推送规则
  • 群组成员导出为项目成员,只要用户在导出的项目群组中具有维护者或管理员角色,

导出:

  • 子流水线历史
  • 构建跟踪和产物
  • 软件包和容器镜像库镜像
  • CI/CD 变量
  • 流水线触发器
  • Webhooks
  • 任何加密令牌
  • 合并请求核准人和所需的批准数量
  • 仓库大小限制
  • 允许推送到受保护分支的部署密钥
  • 安全文件

这些导出规则也适用于从群组实例 级别的模板创建项目,因为使用相同的导出和导入机制。

note有关在项目导出中持久保存的特定数据的更多详细信息,请参阅 import_export.yml 文件。

导入项目及其数据

默认最大导入文件大小从 50 MB 修改为无限制于 13.8 版本。

caution仅从您信任的来源导入项目。如果您从不受信任的来源导入项目,攻击者可能会窃取您的敏感数据。

Prerequisites:

  • 您必须已导出项目及其数据
  • 比较极狐GitLab 版本,并确保您要导入的极狐GitLab 版本比您导出到的极狐GitLab 版本相同或更高。

导入项目:

  1. 新建项目时,选择 导入项目
  2. 导入项目自 中,选择 GitLab导出
  3. 输入您的项目名称和 URL。然后选择您之前导出的文件。
  4. 选择 导入项目 开始导入。您新导入的项目页面很快就会出现。

导入的数据

以下数据将被导入但略有更改:

  • 具有所有者角色的项目成员作为维护者导入。
  • 如果导入的项目包含源自派生项目的合并请求,则在导入/导出期间,在项目中创建与此类合并请求关联的新分支。因此,导出项目中的分支数量可能比原始项目中的多。
  • 如果使用 Internal 可见性级别受到限制,则所有导入的项目可见性都被指定为 Private

未导入部署密钥。要使用部署密钥,您必须在导入的项目中启用它们并更新受保护的分支。

最大导入文件大小

管理员可以通过管理中心 UI 设置最大导入文件大小。

默认值为 0(无限制)。

映射导入的用户

如果管理员(不是所有者)进行导入,则导入的用户可以通过他们在私有化部署实例上的公共电子邮件地址进行映射。

  • 项目必须由具有所有者角色的项目或群组成员导出。
  • 默认情况下未设置公共电子邮件地址。用户必须在他们的配置文件中设置它,才能使映射正常工作。
  • 为了正确映射贡献,用户必须是命名空间的现有成员,或者可以添加为项目的成员。否则,将留下补充评论来提及原始作者和导入者拥有的 MR、注释或议题。
  • 导入的用户在导入的项目中设置为直接成员

速率限制

为了帮助避免滥用,默认情况下,用户的速率限制为:

请求类型 限制
导出 每分钟 6 个项目
下载导出 每个群组每分钟下载 1 个
导入 每分钟 6 个项目

版本历史

14.0+

在 14.0 版本中,项目和群组导出不再支持 JSON 格式。为了允许过渡期,您仍然可以导入任何 JSON 格式的导出。导入和导出的新格式是 NDJSON。

故障排查

由于不匹配,项目无法导入

如果导出的项目与项目导入之间的共享 runner 启用不匹配,则项目无法导入。

  • 确保在源项目和目标项目中都启用了共享 runner。
  • 导入项目时禁用父组上的共享 runner。

大型仓库的导入解决方法

最大导入大小限制可能会阻止导入成功。如果无法更改导入限制,您可以尝试此处列出的解决方法之一。

解决方法 1

以下本地工作流程可用于临时减少仓库大小以进行另一次导入尝试:

  1. 从导出创建一个临时工作目录:

     EXPORT=<filename-without-extension>
    
     mkdir "$EXPORT"
     tar -xf "$EXPORT".tar.gz --directory="$EXPORT"/
     cd "$EXPORT"/
     git clone project.bundle
    
     # Prevent interference with recreating an importable file later
     mv project.bundle ../"$EXPORT"-original.bundle
     mv ../"$EXPORT".tar.gz ../"$EXPORT"-original.tar.gz
    
     git switch --create smaller-tmp-main
    
  2. 要减小仓库大小,请处理这个 smaller-tmp-main 分支:识别和删除大文件交互式变基和修复,来减少提交次数。

     # Reduce the .git/objects/pack/ file size
     cd project
     git reflog expire --expire=now --all
     git gc --prune=now --aggressive
    
     # Prepare recreating an importable file
     git bundle create ../project.bundle <default-branch-name>
     cd ..
     mv project/ ../"$EXPORT"-project
     cd ..
    
     # Recreate an importable file
     tar -czf "$EXPORT"-smaller.tar.gz --directory="$EXPORT"/ .
    
  3. 将这个新的、较小的文件导入极狐GitLab。
  4. 在原始仓库的完整克隆中,使用 git remote set-url origin <new-url> && git push --force --all 完成导入。
  5. 更新导入的仓库的分支保护规则及其默认分支,并删除临时的smaller-tmp-main 分支和本地的临时数据。

解决方法 2

note此解决方法不考虑 LFS 对象。

此解决方法不是尝试一次推送所有更改,而是:

  • 将项目导入与 Git 仓库导入分开
  • 将仓库增量推送到极狐GitLab
  1. 对要迁移的仓库进行本地克隆。在后面的步骤中,您将此克隆推送到项目导出之外。
  2. 下载导出并删除 project.bundle(其中包含 Git 仓库):

    tar -czvf new_export.tar.gz --exclude='project.bundle' @old_export.tar.gz
    
  3. 导入没有 Git 仓库的导出,要求您确认在没有仓库的情况下导入。
  4. 将此 bash 脚本保存为文件,并在添加适当的源后运行它。

    #!/bin/sh
    
    # ASSUMPTIONS:
    # - The GitLab location is "origin"
    # - The default branch is "main"
    # - This will attempt to push in chunks of 500MB (dividing the total size by 500MB).
    #   Decrease this size to push in smaller chunks if you still receive timeouts.
    
    git gc
    SIZE=$(git count-objects -v 2> /dev/null | grep size-pack | awk '{print $2}')
    
    # Be conservative... and try to push 2GB at a time
    # (given this assumes each commit is the same size - which is wrong)
    BATCHES=$(($SIZE / 500000))
    TOTAL_COMMITS=$(git rev-list --count HEAD)
    if (( BATCHES > TOTAL_COMMITS )); then
        BATCHES=$TOTAL_COMMITS
    fi
    
    INCREMENTS=$(( ($TOTAL_COMMITS / $BATCHES) - 1 ))
    
    for (( BATCH=BATCHES; BATCH>=1; BATCH-- ))
    do
      COMMIT_NUM=$(( $BATCH - $INCREMENTS ))
      COMMIT_SHA=$(git log -n $COMMIT_NUM --format=format:%H | tail -1)
      git push -u origin ${COMMIT_SHA}:refs/heads/main
    done
    git push -u origin main
    git push -u origin -—all
    git push -u origin -—tags
    

手动执行导出步骤

导出有时会在没有提供足够信息进行故障排除的情况下失败。在这些情况下,打开 Rails 控制台会话并循环遍历所有定义的 exporter。 单独执行每一行,而不是一次粘贴整个块,这样您就可以看到每个命令返回的任何错误。

# User needs to have permission to export
u = User.find_by_username('someuser')
p = Project.find_by_full_path('some/project')
e = Projects::ImportExport::ExportService.new(p,u)

e.send(:version_saver).send(:save)
e.send(:repo_saver).send(:save)
## continue using `e.send(:exporter_name).send(:save)` going through the list of exporters

# The following line should show you the export_path similar to /var/opt/gitlab/gitlab-rails/shared/tmp/gitlab_exports/@hashed/49/94/4994....
s = Gitlab::ImportExport::Saver.new(exportable: p, shared:p.import_export_shared)

# To try and upload use:
s.send(:compress_and_save)
s.send(:save_upload)