ブランチ上の一部のデータのみをGitHub Pagesで公開する

# 概要
自動生成されるドキュメントをmasterとは別のブランチ上に配置し、GitHub Pagesで公開するための手順の覚え書き。

# 目的
masterブランチに影響を与えることなく、自動生成されるdocs/配下のデータのみをGitHub Pagesで公開する。

# 前提
GitHub Pagesの公開方法は3種類あるが、以下の理由からgh-pagesブランチを公開するものとした。

**masterブランチを公開する**
❌ 不要なデータを公開したくないのでNG。

**ブランチのdocsフォルダを公開する**
❌ `.gitignore`に記述されているような、自動生成されるデータはmasterブランチから除外したいのでNG。

**gh-pagesブランチを公開する**
✅ 上記のいずれも当てはまらないため、消去法で採用。

# 手順
例としてReact+TypeScriptプロジェクトを新規作成し、ドキュメントをTypeDocで生成する場合の手順を示す。

## プロジェクト作成
### プロジェクト作成

```terminal
$ create-react-app docs-in-gh-pages --typescript
$ cd docs-in-gh-pages
```

### リモートリポジトリ登録
GitHub上でリポジトリを作成し、プロジェクトのリモートリポジトリとして登録する。

```terminal
$ git remote add origin git@github.com:hogehoge/docs-in-gh-pages.git
$ git push -u origin master
```

### TypeDocインストール
TypeDocをインストール後、ドキュメントを生成してリモートリポジトリへプッシュする。

```terminal
$ yarn add -D typedoc
$ echo docs/ >> .gitignore # 1.
$ git add .
$ git commit -m "Installed: TypeDoc"
$ git push
```

1. ドキュメントの出力先であるdocs/をリポジトリから除外する。

#### 参照リポジトリ
https://github.com/takuyahara/docs-in-gh-pages/tree/fa4c418835453dc98342749334a470f5e6b8d24a

## GitHub Pagesへの公開
### docs/を公開
GitHub Pagesの公開方法が未設定の状態でgh-pagesブランチが作成されると、自動的にgh-pagesブランチ上のデータが公開されるため、docs/をgh-pagesブランチへプッシュしてドキュメントを公開する。

```terminal
$ git checkout -b gh-pages # 1.
$ node node_modules/.bin/typedoc --out docs src
$ touch docs/.nojekyll # 2.
$ git add docs --force # 3.
$ git commit -m "First docs' commit"
$ git subtree push --prefix docs origin gh-pages # 4.
```

1. `-b`オプションにより、カレントブランチを基準にブランチを新規作成する。
2. GitHub Pagesはページをjekyllで処理して公開するのだが、ファイル名が`_`から始まるファイルはjekyllの仕様で公開されない。TypeDocが生成するほとんどのファイルは`_`から始まるので、jekyllの処理をスキップするため`.nojekyll`を配置する。
3. `.gitignore`にdocs/が記述されているため、`--force`オプションを付けて強制的にステージングする。
4. origin/gh-pagesブランチが存在しないので、新たに作成される。

#### 参照リポジトリ
https://github.com/takuyahara/docs-in-gh-pages/tree/d64143fdc679b4f0ff247f948fd0a64a9a7e99f1

### 事後処理
docs/を公開した後のローカルブランチgh-pagesは不要なため、削除する。

```terminal
$ git checkout master
$ git branch -D gh-pages
```

## ドキュメントの更新
masterブランチ上でコミットが進んでから、ドキュメントを更新してGitHub Pagesに反映する手順を示す。

### masterブランチ上でのコミット
例として、以下のファイルを作成してコミットする。

```json:typedoc.json
{
  "exclude": [
    "src/index.tsx",
    "src/serviceWorker.ts",
    "src/**/*.test.tsx"
  ]
}
```

```terminal
$ git add .
$ git commit -m "Update: some files have excluded"
$ git push
```

#### 参照リポジトリ
https://github.com/takuyahara/docs-in-gh-pages/tree/650a6dbdeeb76012a50fb3da3c69ab33d15277c5

### ドキュメント更新
masterブランチ上の作業に伴ってドキュメントを更新する。手順は[docsを公開](#docsを公開)とほぼ同じだが、ローカルのgh-pagesをorigin/gh-pagesブランチと同期するため、`git subtree add`コマンドを用いること。

この例ではTypeDocの仕様により`git subtree add`にて取得したdoc/を削除している。削除するデータをわざわざ取得するのは冗長に思えるが、`git subtree add`はgh-pagesブランチへの追跡を行うため必ず実行されなければならない。

```terminal
$ git checkout -b gh-pages
$ git subtree add --prefix docs origin gh-pages # 1.
$ rm -rf docs # 2.
$ node node_modules/.bin/typedoc --out docs src
$ touch docs/.nojekyll
$ git add docs --force
$ git commit -m "Second docs' commit"
$ git subtree push --prefix docs origin gh-pages
```

1. docs/が既に存在する場合はエラーになるため、あらかじめ削除しておくこと。
2. 出力先ディレクトリが既存かつ、TypeDocが生成しうるファイル以外のもの（この場合は.nojekyll）が存在するとTypeDocがエラーを起こすため、出力先ディレクトリを削除して後続のコマンドでドキュメントを再作成する。

#### 参照リポジトリ
https://github.com/takuyahara/docs-in-gh-pages/tree/e9b9ec9a6440c831068b89b4c424edc46908cca2

# 考察
`git subtree`コマンドが有効に働き、スマートに目的を達成できた。TypeDocの仕様により`.nojekyll`を毎回作成するのは手間だが、シェルやCIのスクリプトを用いて自動化すれば負担にならないだろう。