物置としての GitHub

ひとりで GitHub を使う場合は **GitHub ≒ 物置** になると思っています。しかし Git/GitHub は煩雑な概念や操作体系を持っており、物置としては少々使いづらいです。

「物置として使いやすくするためにはどうすればいいんだろう」と考え、試行錯誤してきて、ある程度形になったので今回まとめてみます。

※このような GitHub の使い方を便宜上 **GAAS(GitHub As A Storage)** と呼ぶことにします。

# 前提
以下環境を前提としています。

- Windows 7, 10
- git version 2.16.2.windows.1

# GAAS が目指すもの
今回物置として GAAS が目指したい点を明確にしておきます。

## 複数の環境で同期したい
私を取り巻く環境はこんな感じです。

```
   自宅デスクトップPC(Windows)
     A
     |
     V
   GitHub <---> 携帯用PC(MacBookAir)
     A
     |
     V
   実家デスクトップPC(Windows)
```

どの PC からでも簡単に同期を取りたいです。

## 操作を単純にしたい
add, commit, pull/push, fetch, branch, merge... そういうのはもうお腹いっぱいです。極力シンプルに使いたいです。

イメージとしては、

- PC を使い始める時、GitHub から **ダウンロード** を行う
- ...作業...
- PC を使い終える（帰る）前、GitHub に **アップロード** する

これくらいシンプルでいいです。

## 簡単かつ素早く操作したい
もちろん単純にした操作は容易く呼び出せた方がいいです。

コマンドで一発とか、マウスでメニュー開いて選択するだけとか、ダブルクリックするだけとか、それくらいの簡単さと素早さが欲しいです。

## Q: なぜ Dropbox を使わない？
Ans: 以下の点が気に入らないから。

- 複数のクライアントから同時編集した時に競合が起きて面倒くさい
- 同期したくない一時ファイルも同期されてしまう
- バージョン管理できない
- プログラムを常駐させる必要がある（リソースを食う）
- リアルタイムに同期処理が走るのが気持ち悪い

逆に GitHub だと自分のタイミングで同期できますし、バージョン管理もできますし、gitignore で管理対象を適宜除外できたりします。便利なんですよね。

# GAAS の完成形
成果物は（まとめ方が粗いですが） [stakiran/gaas_for_windows](https://github.com/stakiran/gaas_for_windows) にも置いてます。

## 省いた操作
**ブランチ機能全般** は使わないことにしました。

たとえば GAAS では **master(とorigin master) ブランチしか使いません**。実質ブランチは使わないようなものです。これに伴い、Merge だの Rebase だの Pull Request だのそういった煩雑な概念ともおさらばできます。一人物置ならこれでも事足ります。

## 導入した操作
ダウンロード、アップロード、セーブ、ステータス確認といった操作を導入しました。従来の Add, Commit, Push, Pull などをくるんでいます。

| やりたいこと | 実施する操作 | 隠蔽した操作 |
| ------------ | ------------ | ------------ |
| ダウンロード(初回時) | `git clone https://...` |
| ダウンロード | ダウンロード | `git pull` |
| アップロード | アップロード | `git push` |
| 変更を保存(ローカルのみ) | セーブ | `git add`, `git commit` |
| アップロードし忘れの確認 | ステータス確認 | `git status` |

## 操作の呼び出しイメージ
- `save`, `download`, `upload` コマンド
  - どのディレクトリ上からでも呼び出せる
- フォルダの背景(空白)上で右クリック
  - 「Save」「Download」「Upload」メニュー項目が表示される

キーボードからもマウスからもサクサクと呼び出せます。

## 使用プロトコル
HTTPS

## 使用認証
wincred

## ディレクトリ構成
- `D:\work\github\stakiran`
- `D:\work\github\stakiran_sub`

stakiran には「どの PC からもよく使うリポジトリのみ」を clone します。GAAS で扱うのはこのリポジトリ達です。PC から去る場合は必ずアップロードを忘れないようにします。また PC を使う時は最初にダウンロードをします。

stakiran_sub にはそれ以外のリポジトリを clone します。GAAS では扱いません。

## GAAS 利用時の制約
プライベートリポジトリを手に入れるために:

- GitHub の Developer プラン(月7ドルの有料プラン)に加入すること

アップ/ダウンロード時間を肥大化させないために:

- サイズの大きなファイル(100KB以上)はなるべく扱わないこと
- 大量のファイル数(1000以上)はなるべく扱わないこと

トラブらないために:

- (Windows と MacOS を両方使う場合は)日本語ファイル名は扱わないこと
  - 参考: [GitHub 上で同じ日本語ファイル名が二つ存在してしまう問題 - stamemo](http://stakiran.hatenablog.com/entry/2018/01/05/143953)
  - 一言で: Win と MacOS とではファイル名中の濁点の扱いが異なるので（見た目は同じでも文字コード的に差異が出て）同じファイル名が2つ存在するように見えてしまう

# GAAS の実現
以降では GAAS を行うのに必要な設定や考え方をつらつらと書いていきます。

# セーブ/アップロード/ダウンロード
GAAS の肝となるセーブ/アップロード/ダウンロード操作を実現するまでの考え方と手順です。

## (1) 要らない Git 操作を捨てる
- ブランチは `master` のみ使う
  - 理由: 一人用物置なのでブランチを使うまでもない
- リモートブランチは `origin master` のみ使う
  - 理由: 同上
- リモートから引っ張ってくる時は `git pull` のみ使う
  - 理由: fetch してどうこうは面倒くさいので pull で一気に取り込んでしまう

要するにブランチやリモートに絡む部分を削ります。ここまで取捨選択することにより Git/GitHub の扱いがだいぶシンプルになります。

## (2) 「セーブ」と「アップロード」操作をつくる
GitHub にデータをアップロードするには

- ローカルで Add する
- ローカルで Commit する
- ローカルで Push する(リモート側にも反映される)

以上の手順が必要です。いちいちこれらを行うのは面倒くさいですよね。なので隠蔽しちゃいます。

「セーブ」操作は Add と Commit をまとめて行う操作です。「アップロード」操作は Push を行う操作です（セーブ操作を含んじゃってもいいです）。両者とも内部的には以下操作をバッチファイルで隠蔽するだけです。

- `git add -A`
- `git commit -m "コミットメッセージ"`
- `git push origin master`

たとえばセーブ操作を行う save.bat は以下のようになります。

```bat
@echo off
setlocal

rem ★どのディレクトリからでも実行できるようにする
rem   ＆変更点を git status で表示してやるとわかりやすい
pushd %cd%
git status --short
popd

rem ★コミットメッセージを打たせる
rem   ＆こだわりがないなら「u(UpdateのU)」みたいにテキトーでいい
set /p commitmsg="input your commit message>"
if "%commitmsg%"=="" (
	echo A commit message is required.
	exit /b
)
pushd %cd%
echo saving...
git add -A
git commit -m "%commitmsg%"
popd
```

## (3) 「ダウンロード」操作を作る
同じく GitHub からのダウンロード操作も実現します。

これは単純で、`git pull` を隠蔽するだけです。

download.bat の例は以下のとおり。

```bat
@echo off
setlocal

pushd %cd%
echo downloading...
git pull
popd
```

## (4) save, upload, download を簡単に呼び出せるようにする
上記 2, 3 でつくったバッチファイルを簡単に呼び出せるようにします。

### 方法1: PATH を通す
PATH の通ったディレクトリにバッチファイルを配置すると、どのディレクトリ上からでも呼び出せるようになります。

以下は upload コマンドの実行例です。

```terminal
$ cd
D:\work\github\stakiran\qiita

$ dir /b
botsu
gif
img
posted
README.md
XXXX.md
YYYY.md
...

$ upload
input your commit message>u
saving...
[master XXXXXXX] u
 2 files changed, 52 insertions(+), 6 deletions(-)
 ...
To https://github.com/stakiran/qiita
   XXXXXXX..XXXXXXX  master -> master
```

### 方法2: 右クリックメニューから呼び出す
これは Windows のマニアックな機能になりますが、フォルダ背景の右クリックメニューを拡張して、アップロード/ダウンロードを行えるようにします。

レジストリをいじります。詳細は割愛して要点だけ書いときます(regファイルの内容をまんま載せます)。

```reg
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\Background\shell]

[HKEY_CLASSES_ROOT\Directory\Background\shell\git_download]
@="git DOWNLOAD"

[HKEY_CLASSES_ROOT\Directory\Background\shell\git_download\command]
@="\"(GAAS_WORK)\\download.bat\" %V"

[HKEY_CLASSES_ROOT\Directory\Background\shell\git_upload]
@="git UPLOAD"

[HKEY_CLASSES_ROOT\Directory\Background\shell\git_upload\command]
@="\"(GAAS_WORK)\\upload.bat\" %V"

```

以下は実行イメージです。

![gaas_directory_background_menu.jpg](https://qiita-image-store.s3.amazonaws.com/0/191170/a327339d-db3a-4c7d-1c6f-4f32a24da749.jpeg)

# アップロードやダウンロードのし忘れを防ぐ
GAAS ではアップロードやダウンロードのし忘れがよく起きます。

例1: 

- 実家で作業した
- 自宅に戻った
- 「あ、実家PCでアップロードすんの忘れた……」

例2:

- 実家で作業した
- 自宅に戻った
- 自宅で作業した
- アップロードしようとしてコンフリクト発生
  - 「あ、ダウンロードするの忘れてた」

これらを防ぐ必要があります。`git status` や `git pull` あたりを隠蔽すれば実現できそうです。

## (1) GAAS 用ディレクトリを整備する
まず GAAS を運用しやすくするため、ディレクトリ構成をシンプルにする必要があります。具体的には以下のようにします

- ディレクトリ構成
  - `D:\work\github\stakiran`
  - `D:\work\github\stakiran_sub`

stakiran の部分は自分のユーザー名で構いません。以下 stakiran として進めます。

stakiran フォルダには「どの PC からもよく使うリポジトリのみ」を clone します。GAAS で扱うのはこのリポジトリ達です。 **PC から去る場合は必ずアップロードを忘れないようにする** 、また **PC を使う時は最初にダウンロードをする**、この二点を心がけます。

stakiran_sub にはそれ以外のリポジトリを配置します。GAAS では扱いません。

## (2) バッチファイルを配置する
続いてアップロード/ダウンロードのし忘れを確認するためのバッチファイルを配置します。

- 配置例:
  - `D:\work\github\stakiran\statusall.bat` ★アップロードし忘れ確認
  - `D:\work\github\stakiran\pullall.bat`   ★ダウンロードし忘れ確認

あとは、し忘れを確認したい時に、これらバッチファイルを叩くだけです。

## バッチファイルのサンプル

### statusall.bat
まずはアップロードし忘れを確認するバッチファイルを。

```bat
@echo off
setlocal
for /F "usebackq" %%i in (`dir %~dp0 /b /ad`) do (
	if exist %~dp0%%i\.git (
		pushd %~dp0%%i
		echo [%%i]
		git status --short
		git diff origin/master --name-status
		popd
	)
)
pause
```

バッチファイルの読みづらい文法が炸裂していますが、要するに「.git フォルダを持つフォルダ」に対して `git status --short` と `git diff origin/master --name-status` を実行して回ってます。

前者ではコミットのし忘れを、後者ではプッシュのし忘れを表示できます。

以下は実行例です。

![gaas_status_all.jpg](https://qiita-image-store.s3.amazonaws.com/0/191170/1e0f4aa0-96f3-45cf-ed6d-aa3ba570910f.jpeg)

赤い M が「まだコミットが終わってない」、その下の白い M が「まだプッシュが終わってない」を表しています。

### pullall.bat
続いてダウンロードし忘れを確認する方を。

```bat
@echo off
for /F "usebackq" %%i in (`dir %~dp0 /b /ad`) do (
	if exist %%i\.git (
		pushd %%i
		echo [%%i]
		git pull
		popd
	)
)
pause
```

これもアイデアは statusall と同じですが、叩くコマンドが `git pull` になっているだけです（厳密に言うと「ダウンロード済かどうかの確認」というよりも「とりあえずダウンロードする」と言った方が正しいですが）。

これを叩けば全リポジトリに対してダウンロードが実行されます。

「え？コンフリクト回避できなくない？」 はい、そのとおりです。回避はできません。コンフリクトが起きたらそれはその時。頑張って解除しましょう。といっても一人物置なら対して苦労はしないはずです。

# 利用プロトコルと認証方式
GitHub とやりとりするのにどのプロトコルと認証方式を使うか、という話です。

GAAS では以下のようにします。

- プロトコルは **HTTPS** を使う
- 認証は **wincred** を使う

## HTTPS を使う
GitHub と通信するプロトコルとして SSH と HTTPS がありますが、HTTPS を使います。

理由は以下のとおり。

- `git clone (URL)` で clone できるので clone が楽
  - アドレスバーから URL をコピペするだけでいい
- SSH よりも若干通信スピードが速い(体感)

ここは好みだと思うので SSH 派なら SSH で良いと思います。

##  HTTPS 通信時の認証はどうするか
HTTPS プロトコルを使って GitHub と通信する際の問題として認証があります。pull や push の度に毎回 id/password を打つのはだるいです。

そこで Credential helper という設定（もっというと wincred というモード）を使います。wincred を使うと、Windows の「資格情報」という認証機構を利用して id/pass を保存できます。

### 設定方法
gitconfig に設定します。

```
$ git config --global credential.helper wincred
```

Git のバージョンによっては以下も必要かもしれません。

`C:\program files\Git\mingw32\etc\gitconfig` を開き、以下を変更する。

```
[credential]
	helper = manager

↓ 以下のように変更

[credential]
	helper = wincred
```

- 参考:
  - [Caching your GitHub password in Git - User Documentation](https://help.github.com/articles/caching-your-github-password-in-git/)
  - [GitHub への push/pull/clone が突然「error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version」エラーで使えなくなった件 - stamemo](http://stakiran.hatenablog.com/entry/2018/02/24/174941)

### wincred のデメリット
この wincred ですが面倒くさいデメリットがあります。

**複数アカウントに対応していません**。認証設定がグローバルで一つしか保存されない仕様のせいです。

なので、あるアカウント A で認証を保存してしまうと、以後他のアカウントでは HTTPS で GitHub とやり取りできなくなります。

普段は一アカウントしか使わないと思いますが、もし第二アカウントを使う場合は SSH を使いましょう。

# その他 GAAS の制約
その他、GAAS を利用する上で心がけると良い事項を制約として書いておきます。

## 有料プランに加入すること
GitHub は無料プランだと全リポジトリがパブリックとなり、誰でも見ることができます。それでは物置として使い物になりません。プライベートは必須です。

ですがプライベートリポジトリを作成するためには、GitHub の **Developer プラン(月7ドルの有料プラン)** への加入が必要です。

一応 [Secret Gist を使えば疑似プライベート](https://help.github.com/articles/about-gists/#secret-gists) を実現できなくもないですが、

- URL がバレたら中身を見られる
- (実は clone してファイルとか置いて push するというリポジトリ的な使い方もできちゃうのですが)フォルダを作れない

などのデメリットがありイマイチです。

## 大きなファイル or 大量のファイルを扱わないこと
これは単純に Git 操作や GitHub との通信に時間がかかるからです。

私は以下を（なるべく）心がけています。

- 100KB以上 のファイルは扱わない
- 1フォルダ中に1000以上のファイルを置かない

あるいは用途別にリポジトリを分けています。

- 例:
  - text: テキストデータ。軽さ重視。バイナリは置かない。大きなデータも置かない。
  - bin: バイナリデータ。多少ファイルサイズがでかくても容認する。

## 日本語ファイル名を扱わないこと
Windows と MacOS の両方から GitHub を扱う場合は、日本語ファイル名は避けましょう。

というのも、Windows と MacOS とでは **ファイル名中の濁点の扱いが異なる** ため、**（見た目は同じでも文字コード的に差異が出て）同じファイル名が2つ存在するように見えてしまう** という問題が発生します。

- 参考: [GitHub 上で同じ日本語ファイル名が二つ存在してしまう問題 - stamemo](http://stakiran.hatenablog.com/entry/2018/01/05/143953)

## 「し忘れ防止」を確実に呼ぶ仕組みを整える
アップロードし忘れを確認する statusall.bat の例を前述しましたが、これを叩くことを忘れてしまっては意味がありません。忘れないよう一工夫が必要です。

これはタスク管理の領分になるので詳細は割愛しますが、私の場合は [自製したタスク管理ツール tritask](https://qiita.com/sta/items/2b1248869078ac8032d6) を使ってます。tritask を見ながら仕事や作業を進める習慣になっているので、ここに「アップロードし忘れを確認しろ！」的なタスクを置いておくだけで、忘れることなくアップロードできます。

# FAQ
その他関連しそうな話を FAQ という形でまとめておきます。

## Q: バックアップはどうする？
Ans: するかどうかはお好みで ＆ もしするなら .git フォルダを含めるかどうかを考えましょう。

clone したローカルリポジトリのバックアップをどうするかという話です。

「GitHub にあるからいいじゃないか」派なら特に不要ですが、私は単一サービスに全面依存するのは怖いのでバックアップするようにしてます。その際、問題となるのが **.git フォルダをバックアップするかどうか** です。

各ローカルリポジトリにある .git フォルダにはバージョン履歴が全部入っているので、そこそこサイズが大きいです（あとファイル数も多い）。

たとえば私が常用してるテキスト保管リポジトリ text では、

- サイズ 115MB(うち .git フォルダは 106MB)
- ファイル数 5139(うち .git フォルダは 4658)
- ※ちなみにコミット数は 999 でした

このようになっています。

もちろんバックアップするに越したことはないのですが、サイズも食いますし時間もかかります。ケースバイケースでしょうか。ちなみに私はバックアップしてません。

## Q: こんないい加減な運用だと後で履歴を辿れない気がするけど？
Ans: 滅多に辿らないからまあ大丈夫だと思います

一人物置用途では履歴を辿るケースはレアだと思います。

仮に辿る必要性があっても、記憶やら何やらで意外となんとかなります。

私も最初はコミットメッセージやコミット粒度をちゃんとしていたのですが、全然見返さないのに律儀に書く手間がバカらしくなって、今では「u(UpdateのU)」みたいなテキトーなメッセージもよく使います。

ただ、本格的なソフトウェア開発やドキュメント執筆等の場合は、一人でもちゃんと書いた方がいいでしょう。私もそうしてます。

# おわりに
以上、物置という視点で GitHub を捉えてみました。

色々クセは強いですが、今では物置として重宝しています（個人的には Dropbox よりも重宝してます）。皆さんも物置の選択肢として検討してみてはいかがでしょうか :smile:

p.s. GAAS すると [草](https://qiita.com/sta/items/2c1f0252a6a9ce5e2087) が結構エグいことになるかもしれません。

![191116_物置にしてるとこうなる.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191170/8d5fab1d-5ad3-0308-5e15-22867e644662.jpeg)