# Optimizing GitLab for large repositories

> 原文：[https://docs.gitlab.com/ee/ci/large_repositories/](https://docs.gitlab.com/ee/ci/large_repositories/)

*   [Shallow cloning](#shallow-cloning)
*   [Git strategy](#git-strategy)
*   [Git clone path](#git-clone-path)
*   [Git clean flags](#git-clean-flags)
*   [Git fetch extra flags](#git-fetch-extra-flags)
*   [Fork-based workflow](#fork-based-workflow)
    *   [`shell` executor example](#shell-executor-example)
    *   [`docker` executor example](#docker-executor-example)
    *   [Our `.gitlab-ci.yml`](#our-gitlab-ciyml)
    *   [Store custom clone options in `config.toml`](#store-custom-clone-options-in-configtoml)

# Optimizing GitLab for large repositories[](#optimizing-gitlab-for-large-repositories "Permalink")

通常，由于克隆和签出所需的时间，在工作树中包含超过 5 万个文件的大型存储库通常需要特别考虑.

GitLab 和 GitLab Runner 可以很好地处理这种情况，但是需要优化的配置才能有效地执行其操作.

处理大型存储库的一般准则很简单. 以下各节将更详细地描述每个准则：

*   始终以增量方式获取. 请勿以导致重新创建所有工作树的方式进行克隆.
*   始终使用浅克隆来减少数据传输. 请注意，由于 CPU 影响更大，这给 GitLab 实例带来了更多负担.
*   如果您大量使用基于 fork 的工作流，请控制克隆目录.
*   优化`git clean`标志，以确保删除或保留可能影响或加快构建速度的数据.

## Shallow cloning[](#shallow-cloning "Permalink")

在 GitLab Runner 8.9 中引入.

默认情况下，GitLab 和 GitLab Runner 始终执行完整克隆. 虽然这意味着已收到来自 GitLab 的所有更改，但通常会导致接收额外的提交日志.

理想情况下，您应始终使用`GIT_DEPTH` ，该数字应较小，例如 10.这将指示 GitLab Runner 执行浅表克隆. 浅克隆使 Git 仅请求给定分支的最新一组更改，最多达到`GIT_DEPTH`变量定义的所需提交`GIT_DEPTH` .

这极大地加快了从 Git 存储库获取更改的速度，特别是如果存储库积压的事务由很多个大文件组成的积压很长时，因为我们有效地减少了数据传输量.

以下示例使 GitLab Runner 浅表克隆仅获取给定的分支； 它不会获取任何其他分支或标签.

```
variables:
  GIT_DEPTH: 10

test:
  script:
    - ls -al 
```

## Git strategy[](#git-strategy "Permalink")

在 GitLab Runner 8.9 中引入.

默认情况下，GitLab 配置为始终首选`GIT_STRATEGY: fetch`策略. 如果在磁盘上找到`GIT_STRATEGY: fetch`策略，则会重新使用现有的工作树. 这与`GIT_STRATEGY: clone`策略不同， `GIT_STRATEGY: clone`一样，如果找到了工作树，则会在克隆之前将其删除.

首选使用`fetch` ，因为它会减少要传输的数据量，并且不会真正影响您可能会从 CI 对存储库执行的操作.

但是， `fetch`确实需要访问以前的工作树. 使用时，这种运作良好， `shell`或`docker`执行，因为这些努力保持 worktrees，默认情况下尽量重复使用它们.

目前不适用于`kubernetes`执行器，并且在使用`kubernetes` `docker+machine`时有限制. `kubernetes`执行器总是克隆到临时目录中.

GitLab 还提供了`GIT_STRATEGY: none`策略. 这会禁用任何由 GitLab 完成的`fetch`和`checkout`命令，要求您执行这些操作.

## Git clone path[](#git-clone-path "Permalink")

在 GitLab Runner 11.10 中引入.

[`GIT_CLONE_PATH`](../yaml/README.html#custom-build-directories)允许您控制在何处克隆源. 如果您在 fork 工作流中大量使用大型存储库，则可能会产生影响.

从 GitLab Runner 的角度来看，前叉工作流存储为具有单独工作树的单独存储库. 这意味着 GitLab Runner 无法优化工作树的使用，您可能必须指示 GitLab Runner 使用它.

在这种情况下，理想情况下，您希望使 GitLab Runner 执行程序仅用于给定项目，而不是在不同项目之间共享，以使此过程更高效.

[`GIT_CLONE_PATH`](../yaml/README.html#custom-build-directories)必须在`$CI_BUILDS_DIR` . 当前，不可能从磁盘选择任何路径.

## Git clean flags[](#git-clean-flags "Permalink")

在 GitLab Runner 11.10 中引入.

[`GIT_CLEAN_FLAGS`](../yaml/README.html#git-clean-flags)允许您控制是否要求对每个 CI 作业执行`git clean`命令. 默认情况下，GitLab 确保您的工作树在给定的 SHA 上，并且您的存储库是干净的.

设置为`none`时，将禁用[`GIT_CLEAN_FLAGS`](../yaml/README.html#git-clean-flags) . 在非常大的存储库上，这可能是理想的，因为`git clean`是磁盘 I / O 密集型的. 使用`GIT_CLEAN_FLAGS: -ffdx -e .build/`控制`GIT_CLEAN_FLAGS: -ffdx -e .build/` （例如）使您可以控制和禁用后续运行之间工作树中某些目录的删除，这可以加快增量生成的速度. 如果您重复使用现有计算机并拥有可用于构建的现有工作树，则效果最大.

有关[`GIT_CLEAN_FLAGS`](../yaml/README.html#git-clean-flags)接受的确切参数，请参见[`git clean`](https://git-scm.com/docs/git-clean)的文档. 可用参数取决于 Git 版本.

## Git fetch extra flags[](#git-fetch-extra-flags "Permalink")

在 GitLab Runner 13.1 中[引入](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4142) .

[`GIT_FETCH_EXTRA_FLAGS`](../yaml/README.html#git-fetch-extra-flags) allows you to modify `git fetch` behavior by passing extra flags.

有关更多信息，请参见[`GIT_FETCH_EXTRA_FLAGS`文档](../yaml/README.html#git-fetch-extra-flags) .

## Fork-based workflow[](#fork-based-workflow "Permalink")

在 GitLab Runner 11.10 中引入.

遵循以上准则，让我们假设我们想要：

*   针对大型项目进行优化（目录中有超过 5 万个文件）.
*   使用基于分叉的工作流进行贡献.
*   重用现有的工作树. 预先配置了存储库的预配置运行器.
*   赛跑者仅分配给项目和所有分叉.

让我们考虑以下两个示例，一个使用`shell` executor，另一个使用`docker` executor.

### `shell` executor example[](#shell-executor-example "Permalink")

假设您具有以下[`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html) .

```
concurrent = 4

[[runners]]
  url = "GITLAB_URL"
  token = "TOKEN"
  executor = "shell"
  builds_dir = "/builds"
  cache_dir = "/cache"

  [runners.custom_build_dir]
    enabled = true 
```

This `config.toml`:

*   使用`shell`执行器，
*   指定一个自定义`/builds`目录，其中将存储所有克隆.
*   启用指定`GIT_CLONE_PATH` ，
*   一次最多运行 4 个作业.

### `docker` executor example[](#docker-executor-example "Permalink")

假设您具有以下[`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html) .

```
concurrent = 4

[[runners]]
  url = "GITLAB_URL"
  token = "TOKEN"
  executor = "docker"
  builds_dir = "/builds"
  cache_dir = "/cache"

  [runners.docker]
    volumes = ["/builds:/builds", "/cache:/cache"] 
```

This `config.toml`:

*   使用`docker` executor，
*   在磁盘上指定将存储所有克隆的自定义`/builds`目录. 我们在主机上挂载`/builds`目录，以使其在后续运行之间可重复使用，并允许其覆盖克隆策略.
*   默认情况下已启用，因此未启用指定`GIT_CLONE_PATH`功能.
*   一次最多运行 4 个作业.

### Our `.gitlab-ci.yml`[](#our-gitlab-ciyml "Permalink")

一旦配置了执行程序，就需要微调`.gitlab-ci.yml` .

Our pipeline will be most performant if we use the following `.gitlab-ci.yml`:

```
variables:
  GIT_DEPTH: 10
  GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME

build:
  script: ls -al 
```

上面配置了：

*   浅克隆 10，以加快后续`git fetch`命令的速度.
*   自定义克隆路径，使我们可以在父项目和所有分支之间重用工作树，因为我们对所有分支使用相同的克隆路径.

为什么要使用`$CI_CONCURRENT_ID` ？ 主要原因是要确保使用的工作树在项目之间不冲突. `$CI_CONCURRENT_ID`表示给定执行器中的唯一标识符，因此只要我们使用它来构造路径，就可以确保该目录不会与其他正在运行的并发作业冲突.

### Store custom clone options in `config.toml`[](#store-custom-clone-options-in-configtoml "Permalink")

理想情况下，所有与作业相关的配置都应存储在`.gitlab-ci.yml` . 但是，有时希望使这些方案成为 Runner 配置的一部分.

在以上 Forks 的示例中，使此配置对于用户可发现可能是首选，但这会带来管理开销，因为需要为每个分支更新`.gitlab-ci.yml` . 在这种情况下，可能希望保持`.gitlab-ci.yml`克隆路径不可知，但是将其配置为 Runner.

我们可以使用以下规范扩展[`config.toml`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html) ，如果`.gitlab-ci.yml`不覆盖它，它将由 Runner 使用：

```
concurrent = 4

[[runners]]
  url = "GITLAB_URL"
  token = "TOKEN"
  executor = "docker"
  builds_dir = "/builds"
  cache_dir = "/cache"

  environment = [
    "GIT_DEPTH=10",
    "GIT_CLONE_PATH=$CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_NAME"
  ]

  [runners.docker]
    volumes = ["/builds:/builds", "/cache:/cache"] 
```

这使得克隆配置成为给定 Runner 的一部分，并且不需要我们更新每个`.gitlab-ci.yml` .