# Moving repositories managed by GitLab

> 原文：[https://docs.gitlab.com/ee/administration/operations/moving_repositories.html](https://docs.gitlab.com/ee/administration/operations/moving_repositories.html)

*   [Target directory is empty: use a tar pipe](#target-directory-is-empty-use-a-tar-pipe)
    *   [Tar pipe to another server](#tar-pipe-to-another-server)
*   [The target directory contains an outdated copy of the repositories: use rsync](#the-target-directory-contains-an-outdated-copy-of-the-repositories-use-rsync)
    *   [Single rsync to another server](#single-rsync-to-another-server)
*   [Thousands of Git repositories: use one rsync per repository](#thousands-of-git-repositories-use-one-rsync-per-repository)
    *   [Parallel rsync for all repositories known to GitLab](#parallel-rsync-for-all-repositories-known-to-gitlab)
    *   [Parallel rsync only for repositories with recent activity](#parallel-rsync-only-for-repositories-with-recent-activity)

# Moving repositories managed by GitLab[](#moving-repositories-managed-by-gitlab "Permalink")

有时，您需要将 GitLab 管理的所有存储库移至另一个文件系统或另一个服务器. 在本文档中，我们将介绍将所有存储库从`/var/opt/gitlab/git-data/repositories` `/mnt/gitlab/repositories`到`/mnt/gitlab/repositories` .

我们将研究三种情况：目标目录为空，目标目录包含版本库的过时副本，以及如何处理数千个版本库.

**我们列出的每种方法都可以/将覆盖目标目录`/mnt/gitlab/repositories` . 不要混淆源和目标.**

## Target directory is empty: use a tar pipe[](#target-directory-is-empty-use-a-tar-pipe "Permalink")

如果目标目录`/mnt/gitlab/repositories`为空，则最简单的操作是使用 tar 管道. 此方法的开销很低，并且 tar 几乎总是已安装在系统上. 但是，无法恢复中断的 tar 管道：如果发生这种情况，则必须再次复制所有数据.

```
sudo -u git sh -c 'tar -C /var/opt/gitlab/git-data/repositories -cf - -- . |\
  tar -C /mnt/gitlab/repositories -xf -' 
```

如果要查看进度，请用`-xvf`替换`-xf` .

### Tar pipe to another server[](#tar-pipe-to-another-server "Permalink")

You can also use a tar pipe to copy data to another server. If your `git` user has SSH access to the new server as `git@newserver`, you can pipe the data through SSH.

```
sudo -u git sh -c 'tar -C /var/opt/gitlab/git-data/repositories -cf - -- . |\
  ssh git@newserver tar -C /mnt/gitlab/repositories -xf -' 
```

如果您想在数据通过网络之前进行压缩（这将花费您的 CPU 周期），则可以将`ssh`替换为`ssh -C` .

## The target directory contains an outdated copy of the repositories: use rsync[](#the-target-directory-contains-an-outdated-copy-of-the-repositories-use-rsync "Permalink")

如果目标目录已经包含部分/过时的存储库副本，那么再次用 tar 复制所有数据可能会很浪费. 在这种情况下，最好使用 rsync. 该实用程序已经安装在系统上，也可以通过 apt，yum 等轻松安装.

```
sudo -u git  sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
  /mnt/gitlab/repositories' 
```

`/.` 在上面的命令中非常重要，没有它，您很容易在目标目录中获得错误的目录结构. 如果要查看进度，请用`-av`替换`-a` .

### Single rsync to another server[](#single-rsync-to-another-server "Permalink")

如果源系统上的`git`用户对目标服务器具有 SSH 访问权限，则可以使用 rsync 通过网络发送存储库.

```
sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
  git@newserver:/mnt/gitlab/repositories' 
```

## Thousands of Git repositories: use one rsync per repository[](#thousands-of-git-repositories-use-one-rsync-per-repository "Permalink")

每次启动 rsync 作业时，它都必须检查源目录中的所有文件，目标目录中的所有文件，然后确定要复制或不复制哪些文件. 如果源目录或目标目录中包含许多内容，则 rsync 的启动阶段可能会成为您的 GitLab 服务器的负担. 在这种情况下，可以通过将 rsync 的工作分成较小的部分来使 rsync 的工作变得更轻松，并一次同步一个存储库.

除了 rsync 之外，我们还将使用[GNU Parallel](http://www.gnu.org/software/parallel/) . 该实用程序未包含在 GitLab 中，因此您需要使用 apt 或 yum 自己安装. 还要注意，我们在下面使用的 GitLab 脚本是在 GitLab 8.1 中添加的.

**此过程不会清理源位置不再存在的目标位置的存储库.** 如果您开始在`/mnt/gitlab/repositories`使用 GitLab 实例，则需要在切换到新的存储库存储目录后运行`gitlab-rake gitlab:cleanup:repos` .

### Parallel rsync for all repositories known to GitLab[](#parallel-rsync-for-all-repositories-known-to-gitlab "Permalink")

这将一次将存储库与 10 个 rsync 进程同步. 我们会跟踪进度，以便在必要时可以重新开始传输.

首先，我们创建一个新目录，由`git`拥有，以保存传输日志. 在开始传输过程之前，我们假定目录为空，并且我们是唯一在其中写入文件的目录.

```
# Omnibus
sudo mkdir /var/opt/gitlab/transfer-logs
sudo chown git:git /var/opt/gitlab/transfer-logs

# Source
sudo -u git -H mkdir /home/git/transfer-logs 
```

我们使用要复制的目录列表为该过程添加种子.

```
# Omnibus
sudo -u git sh -c 'gitlab-rake gitlab:list_repos > /var/opt/gitlab/transfer-logs/all-repos-$(date +%s).txt'

# Source
cd /home/git/gitlab
sudo -u git -H sh -c 'bundle exec rake gitlab:list_repos > /home/git/transfer-logs/all-repos-$(date +%s).txt' 
```

现在我们可以开始传输了. 下面的命令是幂等的，并且 GNU Parallel 完成的作业数应收敛为零. 如果不是这样，则`all-repos-1234.txt`列出的某些存储库在被复制之前可能已被删除/重命名.

```
# Omnibus
sudo -u git sh -c '
cat /var/opt/gitlab/transfer-logs/* | sort | uniq -u |\
  /usr/bin/env JOBS=10 \
  /opt/gitlab/embedded/service/gitlab-rails/bin/parallel-rsync-repos \
    /var/opt/gitlab/transfer-logs/success-$(date +%s).log \
    /var/opt/gitlab/git-data/repositories \
    /mnt/gitlab/repositories
'

# Source
cd /home/git/gitlab
sudo -u git -H sh -c '
cat /home/git/transfer-logs/* | sort | uniq -u |\
  /usr/bin/env JOBS=10 \
  bin/parallel-rsync-repos \
    /home/git/transfer-logs/success-$(date +%s).log \
    /home/git/repositories \
    /mnt/gitlab/repositories
` 
```

### Parallel rsync only for repositories with recent activity[](#parallel-rsync-only-for-repositories-with-recent-activity "Permalink")

假设您已经完成了一次在 2015 年 10 月 1 日 12:00 UTC 之后开始的同步. 然后，您可能只想同步*在*那*之后*通过 GitLab 更改的存储库. 您可以使用`SINCE`变量告诉`rake gitlab:list_repos`仅打印具有最近活动的存储库.

```
# Omnibus
sudo gitlab-rake gitlab:list_repos SINCE='2015-10-1 12:00 UTC' |\
  sudo -u git \
  /usr/bin/env JOBS=10 \
  /opt/gitlab/embedded/service/gitlab-rails/bin/parallel-rsync-repos \
    success-$(date +%s).log \
    /var/opt/gitlab/git-data/repositories \
    /mnt/gitlab/repositories

# Source
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:list_repos SINCE='2015-10-1 12:00 UTC' |\
  sudo -u git -H \
  /usr/bin/env JOBS=10 \
  bin/parallel-rsync-repos \
    success-$(date +%s).log \
    /home/git/repositories \
    /mnt/gitlab/repositories 
```