GitBucketからGitLabへの移行

# やること

稼働中のGitBucketの全グループ、プロジェクト(リポジトリ)を新規に構築したGitLab(Community Edition)へ移行します。

基本的に他のGitリポジトリホスティングサービスでも概ね使えるんじゃないかと思いますが、

移行先がGitLabでない場合には、GitLab CLIの部分を適宜置き換える必要があります。

## 環境、条件等

### 移行元
* OS: CentOS6
* GitBucket: 3.0

### 移行先(新規構築)
* OS: CentOS7
* GitLab: 8.15.4

## 作業の流れ

1. GitLabサーバの構築
    1. CentOS7をInstall
    1. GitLabをインストール
    1. GitLabCLIをインストール 
1. リポジトリ群の移行
    1. GitBucket側でグループとリポジトリのリストを取得
    1. 取得したリストをもとにGitLab CLI でグループ群を作成
    1. 取得したリストをもとにGitLab CLI でプロジェクト群を作成
    1. 全プロジェクトをgitコマンドでGitBucketからCloneしてGitLabへPush
    1. 各自のremoteをGitLabへ変更

# GitLabサーバの構築

1. CentOS7をInstall

1. GitLabをインストール

    1. インストール手順は[オフィシャル](https://about.gitlab.com/downloads/)を参照

1. GitLabCLIをインストール

    1. [オフィシャル](https://about.gitlab.com/applications/)にある[Narkoz's Ruby wrapper & CLI](https://github.com/NARKOZ/gitlab)を使用する

    1. インストール前に必要なパッケージをインストール

        ```bash
        yum install -y gcc ruby-devel gem
        gem install gitlab
        ```

    1. [README.md](https://github.com/NARKOZ/gitlab)に従ってインストール

        ```bash
        gem install gitlab
        ```

    1. GitLabでAccessTokenを発行する

    1. 設定ファイルを修正

        ```bash
        vi /usr/local/share/gems/gems/gitlab-3.7.0/lib/gitlab/configuration.rb
        ```

        ```ruby:configuration.rb
          :
        def reset
          self.endpoint       = 'http://changeIt/api/v3'
          self.private_token  = 'AccessToken'
            :
        end
          :
        ```
    
    1. コマンドを実行して結果が得られることを確認

        ```bash
        gitlab
        gitlab users
        gitlab groups
        ```

# リポジトリ群の移行

## リポジトリ移行時の注意

当初、適当なGitClientからCloneしてPushすればOKでしょ。と思っていたがこれはダメ。

何がダメかというと

1. Clone,Pushしたブランチしか移行できない

1. Tagが移行できない

下記の手順ですべての管理情報を含む移行ができる。

GitBucket上のSample/Appを、GitLabへ移行する場合の例

```bash
git clone --mirror https://gitbucket/Sample/App.git
cd App.git
git push --mirror https://gitlab/Sample/App.git
```

GitBucketもGitLabもWikiページをリポジトリとして管理するのでこれも同様に移行可能

```bash
git clone --mirror https://gitbucket/Sample/App.wiki.git
cd App.wiki.git
git push --mirror https://gitlab/Sample/App.wiki.git
```

これを踏まえ実際に移行作業へ。

## 手順詳細

1. GitBucket側でグループとリポジトリのリストを取得

    1. どんな方法でもいいけど今回は `locate` で抽出しました。

        ```bash
        locate *.git > gitList.txt
        ```

        1. `find . -type d ` でも `tree` でも。職人さんは手作業でもいいかも。

            ```bash
            find /var/opt/gitbucket/git-data/repositories -type d -name *.git > gitList.txt
            tree -L 2 /var/opt/gitbucket/git-data/repositories > gitList.txt
            ```

1. 取得したリストをもとにGitLab CLI でグループ群を作成

    下記のグループ作成コマンドでloopして作成します。

    全グループのみを抽出したテキストファイル`groups.txt`をもとに処理する場合。とりあえずPublicで作成。

    ```bash
    cat groups.txt | while read GROUP; do
        gitlab create_group ''${GROUP}'' ''${GROUP}'' "{ description: '${GROUP}', visibility_level: 20 }"
    done
    ```

    詳細は下記の通り。

    gitlabコマンドのヘルプ

    ```bash
    gitlab help
    gitlab help Groups
    gitlab help create_group
    gitlab help add_group_memer
    ```

    グループ作成コマンド

    例:Sampleグループ

    ```bash
    gitlab create_group 'Sample' 'Sample' "{ description: 'Sample', visibility_level: 0 }"
    ```

    [visibility_levelは3種類](https://docs.gitlab.com/ce/api/groups.html#new-group)

    | visibility_level | Group's visibility |
    |:-----------------|:-------------------|
    |  0               | private            |
    | 10               | internal           |
    | 20               | public             |

    visibility_level を private に設定した場合その後メンバーを追加する必要があります。

    メンバーの追加は、`git add_group_member`で。

    例: Hoge(id:1)をSampleグループ(id:9)にaccessLevel30(Developer)で追加

    ```bash
    gitlab add_group_memer 3 1 30
    ```

    [accessLevelは5種類](https://docs.gitlab.com/ce/api/members.html#group-and-project-members)

    |accessLevel|定義|
    |:------------|:----------|
    | 10          | Guest     |
    | 20          | Reporter  |
    | 30          | Developer |
    | 40          | Master    |
    | 50          | Owner     |

1. 取得したリストをもとにGitLab CLI でプロジェクト群を作成

    下記のプロジェクト作成コマンドでloopして作成します。

    下記のような全プロジェクトと対応するグループIDを抽出したテキストファイル`projects.txt`をもとに処理する。

    ```txt:projects.txt
    SampleHoge,2
    SamplPiyo,2
    SampleFuga,3
    ```

    コマンド

    ```bash
    cat projects.txt | while read LINE; do
        PROJECT=`echo ${LINE} | cut -d',' -f 1`
        GROUPID=`echo ${LINE} | cut -d',' -f 2`
        gitlab create_project ''${PROJECT}'' "{ description: '${PROJECT}', namespace_id: '${GROUPID}' }"
    done
    ```

    詳細は下記の通り。

    gitlabコマンドのヘルプ

    ```bash
    gitlab help
    gitlab help Projects
    gitlab help create_project
    ```

1. 全プロジェクトをgitコマンドでGitBucketからCloneしてGitLabへPush

    下記のようなGitBucketとGitLabのリポジトリのリスト`repos.txt`をもとに処理する。

    ```txt:repos.txt
    https://gitbucket/SampleHoge/App.git,https://gitlab/SampleHoge/App.git
    https://gitbucket/SampleHoge/App.wiki.git,https://gitlab/SampleHoge/App.wiki.git
    https://gitbucket/SamplePiyo/App.git,https://gitlab/SamplePiyo/App.git
    https://gitbucket/SamplePiyo/App.wiki.git,https://gitlab/SamplePiyo/App.wiki.git
    https://gitbucket/SampleFuga/App.git,https://gitlab/SampleFuga/App.git
    https://gitbucket/SampleFuga/App.wiki.git,https://gitlab/SampleFuga/App.wiki.git
    ```

    コマンド

    ```bash
    cat repos.txt | while read LINE; do
        if [ 0 -eq `echo ${LINE} | grep -c '.git'` ]; then
            continue
        fi
        SRC=`echo ${LINE} | cut -d',' -f 1`
        DST=`echo ${LINE} | cut -d',' -f 2`
        DIR=`echo ${SRC} | awk -F / '{print $NF}'`
        git clone --mirror ${SRC}
        cd ${DIR}
        git push --mirror ${DST}
        cd ..
    done

    ```

1. 各自のremoteをGitLabへ変更

    可能であれば移行前にすべて変更をCommit&Pushしておいてもらい、移行後にGitLabからcloneし直してもらうのが良い。

    が、それが困難な場合には既存のremoteのURLを更新します。

    ```bash
    git remote set-url origin https://gitlab/SampleHoge/App.git
    ```