Git Action でリポジトリのミラーを行う

# 要件

 - リポジトリを他人と共有したい
 - 特定の人物には閲覧のみさせたい。もしくは push を無効にしたい
 - 閲覧できるソースの範囲を限定したい

# 対応

 - リポジトリを別のリポジトリにミラーコピーして、そのリポジトリを共有する
 - git push された際に、Git Action で自動的にミラーコピーできるように設定する

# 手順

## 01. ミラー先リポジトリを作成する【ブラウザ：ミラー先リポジトリ】

ブラウザから Github に入り、 アカウントのリポジトリリストから `New` で、空のリポジトリを作成します。
READMEを作成するにチェックを入れると、リポジトリがすぐに作成されるのでそちらの方が楽だと思います。
中身は手動では何も入れなくて大丈夫です。

## 02. パスフレーズなしのSSH鍵を生成する【ローカル】

Action では対話ができないので、通常のSSH鍵ではなく、パスフレーズなしのSSH鍵を指定する必要があります。
そのためのSSH鍵を作成します。
**ミラー先（閲覧用）** のリポジトリをcloneする際のSSH鍵のある場所に移動します。

```bash
$ cd .ssh
```

パスフレーズなしのSSH鍵を生成します。
OpenSSHの構成が `OpenSSH 7.8` から変わりヘッダが `-----BEGIN RSA PRIVATE KEY-----` から `-----BEGIN OPENSSH PRIVATE KEY-----` に変わり、ActionでのSSH接続が失敗する場合があります。
その対策のため、 `-m PEM` をオプションに追加してSSH鍵を生成してください。

```bash
$ ssh-keygen -t rsa -b 4096 -m PEM -C <githubアカウントメールアドレス>
```

SSH鍵の名前を `id_rsa_nopass` にして生成します。
**（id_rsaのままだと上書きしてしまうので注意してください。）**
怖い場合は、`.ssh-nopass` とか別のフォルダを作成して、その中で作業すると安全だと思います。

```bash
Generating public/private rsa key pair.
Enter file in which to save the key (/<ユーザーディレクトリ>/.ssh/id_rsa): ./id_rsa_nopass
```

パスフレーズには何も入力せず、Enterで進みます。

```bash

Enter same passphrase again:
Your identification has been saved in ./id_rsa_nopass.
Your public key has been saved in ./id_rsa_nopass.pub.
The key fingerprint is:
<フィンガープリント> <githubアカウントメールアドレス>
The key's randomart image is:
+---[RSA 4096]----+
（略）
+----[SHA256]-----+
```

参考：[【OpenSSH 7.8】秘密鍵を生成する形式が変更になった件について](https://dev.classmethod.jp/server-side/network/openssh78_potentially_incompatible_changes/)

## 03. git secret に秘密鍵を登録する【ブラウザ：ミラー元リポジトリ】

先ほど作成した秘密鍵を、リポジトリの　`secret`（暗号化領域） に登録します。

参考：　[Githubの secret について](https://help.github.com/ja/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets)

**ミラー元（作業用）** のリポジトリの `Settings` ＞ `Secrets` を開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/36e53e41-2a96-2c85-da44-7682d735465a.png)

`Add a new secret` のリンクを押下します。
secret登録欄が開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/64d99491-9d80-6aac-4fb9-5dce93c80e2e.png)

**id_rsa_nopass（秘密鍵）** の内容をクリップボードにコピーします。

```bash
$ clip < ./id_rsa_nopass
```

`Name` 欄に `SSH_PRIVATE_KEY` と入力します。
`Value` 欄で、Ctrl+Vで、クリップボードにコピーした内容を貼り付けます。

`Add secret` ボタンを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/2bbe71e0-72d7-9601-6028-2623c4a37c03.png)

このように登録されていたらOKです。

## 04. SSH鍵を登録する【ブラウザ：アカウント】

SSH公開鍵を登録して、SSHログインができるようにします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/2767d773-9ce4-ec29-1661-74db462124a6.png)

githubのアイコンから `Settings`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/2e119ad1-e60c-8093-8ee9-7144ddfe0ac9.png)

Settings メニューから `SSH and GPG keys` を選択し、SSH keysの「New SSH key」を選択します。

一旦、git bash に戻って、公開鍵キーをクリップボードにコピーします。

```bash
$ clip < ./id_rsa_nopass.pub
```

Key欄にペーストします。
Titleは任意のキー名（半角英数がよいでしょう）を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/f5e7c38a-3cfe-c0fe-fecf-dcb6d60f9dfb.png)

「Add SSH Key」をクリックするとパスワードを求められるので入力確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/8975a193-895a-5a32-cc13-1007de949f74.png)

登録が完了すると、キー名とフィンガープリントが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/c6894129-bb6d-9bcf-b5d8-d270930a8008.png)

github に SSH接続します。
SSH鍵を<ユーザディレクトリ>以外で作成した場合、`-i`オプションで鍵のパスを指定する必要があります。
SSH鍵のパスフレーズなしに接続できることを確認します。

```bash
$ ssh -T git@github.com -i ./id_rsa_nopass
Hi miu200521358! You've successfully authenticated, but GitHub does not provide shell access.
```

参考：[Testing your SSH connection](https://help.github.com/en/github/authenticating-to-github/testing-your-ssh-connection)


## 05. .gitattributes を登録する【ブラウザ：ミラー元リポジトリ】

**ミラー元（作業用）** のリポジトリのルートに `.gitattributes` がない場合、新規ファイルを作成してください。
既にある場合は、そのファイルに下記を追記してください。

```
.github/ export-ignore
.git*    export-ignore
```

これは、Actionが保存される `github/workflow` のフォルダと、`.gitattributes` 等、gitの設定ファイルを、export時に除外する、という指定です。
この指定を追加していくことで、**ミラー先（閲覧用）** のリポジトリにミラーコピーされるファイルをコントロールできます。

## 06. Git Action を登録する【ブラウザ：ミラー元リポジトリ】

**ミラー元（作業用）** のリポジトリのメニューから `Actions` を押下します。
新規Actionに登録するワークフローを選べますが、無視して右上の `Set up a workflow yourself` をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/6b6b1426-3743-887a-c79c-5e224e629b32.png)

このような入力画面が出てきたら、下記コードを適当なテキストエディタにコピーしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/b4ca412d-e4a9-699e-3e3c-38c73757da50.png)

下記コードの設定項目（env: の下の <日本語の項目>）を書き換えて、既存のコードはすべて削除した上で、下記コード全文を `main.yml` に貼り付けてください。
コメントもそのまま貼り付け可能です。

```yaml
name: Mirror Repository 

on:
  push:
    branches:
      - master  # branch:master に対する push が行われた時にのみ処理を実行する
jobs:
  build:
    runs-on: ubuntu-latest  # 最新のubuntuイメージを使用する
    env:
      # ミラー先リポジトリ名
      MIRROR_REPOSITORY_NAME: <ミラー先リポジトリ名>
      # ミラー先のリポジトリSSHパス
      MIRROR_RIPOSITORY:  <ミラー先リポジトリのclone用SSHパス(git:github～っての)>
      # gitアカウント名(git config user.name）
      GIT_NAME: <Github のアカウント名>
      # gitメールアドレス（git config user.email）
      GIT_MAILADDRESS: <Github のメールアドレス>
    steps:
    - uses: actions/checkout@v2
    - name: set-git
      run: |
        git config --global user.name $GIT_NAME
        git config --global user.email $GIT_MAILADDRESS
    - name: set-ssh
      run: |
        mkdir ~/.ssh                                            # SSHディレクトリ作成
        chmod 700 ~/.ssh                                        # 権限を設定
        echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa   # secretに保存されているパスフレーズなしの秘密鍵を出力する
        chmod 600 ~/.ssh/id_rsa                                 # 権限を限定する
    - name: clone
      run: |
        mkdir ~/mirror                                          # ミラー用ディレクトリ作成
        cd ~/mirror                                             # ミラー用ディレクトリに移動
        git clone $MIRROR_RIPOSITORY                            # ミラー用リポジトリをclone
        echo | ls -l ./                                         # ファイル存在確認
    - name: export
      run: |
        git archive --format=zip HEAD > ~/original.zip          # リポジトリの最新ソースを zip でexportする
        echo | ls -l ~/original.zip                             # ファイル存在確認
        mkdir ~/original                                        # 保持用ディレクトリ作成
        unzip -o -d ~/$MIRROR_REPOSITORY_NAME ~/original.zip    # zipを展開する(既存上書き)
        echo | ls -l ~/$MIRROR_REPOSITORY_NAME                  # 中身表示
    - name: copy
      run: |
        cp -r ~/$MIRROR_REPOSITORY_NAME ~/mirror                # オリジナルをミラーにコピーする
        echo | ls -l ~/mirror/$MIRROR_REPOSITORY_NAME           # 中身表示
    - name: push
      run: |
        cd ~/mirror/$MIRROR_REPOSITORY_NAME                     # ミラー用リポジトリに移動
        echo | ls -l                                            # 中身表示
        git diff                                                # 差分表示
        git add -A                                              # 全部追加
        git commit -m "mirror from original"                    # commit
        git push origin master                                  # push

```

コピペできたら、右上の`Start commit`を押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/79244511-d0aa-91a4-2501-a22f027e37a3.png)

直接 push してしまって良い場合は上のラジオボタン、pull request を生成する場合は下のラジオボタンを選択してください。
上のラジオボタンを選択して commit した場合、直後に Action が実行されます。
下のラジオボタンの場合、pull request をマージしたタイミングで Action が実行されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/201b3d75-f9f7-fd48-836e-8cc788a4d0b7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/f8d49b4d-febc-ea5e-fb37-8e328310cce4.png)

実際のログを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/4aeeac30-b7e8-f7fd-40dd-95befd0cf542.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/37bbc09e-d002-ebef-fc33-0acb499f5776.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/3d8a62ae-93d4-dce9-5e03-1e8c7d9b543e.png)
（どの項目にも簡単なログを出してます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/d0bc90fa-b287-439b-1b5d-281100d09639.png)

このように、緑のチェックマークがついていれば、その処理は成功しています。
赤い×だと失敗しているので、中を確認してください。

## 07. ミラー先を確認する【ブラウザ：ミラー先リポジトリ】

ミラー先リポジトリを確認すると、初回は全ファイルがcommitされています。
2回目以降は、更新のあったファイルがあげられています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254327/9717e205-85bb-bb57-74a3-7678026e3ad6.png)

## 蛇足

Git Action では、デプロイやtest等、様々なワークフローが実行できます。
herokuへの自動リリースもできると思います。

以上