GitPython / git-ftp.py を使って git commit した時に FTP アップロードも行う方法

# 経緯
FTPには編集したファイルのみをアップロードすべきだと思っています。

開発しながらアップして、という感じで、量が少なければいいのですが
jpgを50枚近く差し替え(しかもディレクトリがばらばら)みたいな依頼があって
手動でやるのが億劫だったので何か良い方法はないかと思ったところ
git と Pythonでできそうだったのでやってみたメモ。

最近は git push した時に自動でデプロイなんて方法がいくらかあるようですが
事情により ssh 接続できない。。ということがあったので方法の一つとしてやることにしました。

また、 [git-ftp](https://github.com/git-ftp/git-ftp) を使うともっと簡単にアップできるようだったのですが、
初回に `git ftp init` をして、リポジトリにある全ファイルをFTPでアップしないといけなかったりと、
ちょっといろんな人に影響がでそうだったので(サーバーはみんなのもの。。)今回の方法を行いました。

ちなみに Python はど素人。

## GitPython とは
[GitPython](https://gitpython.readthedocs.io/en/stable/intro.html) は git を Python から扱えるようにした Python のライブラリ

## git-ftp.py とは
[git-ftp.py](https://github.com/ezyang/git-ftp/blob/master/README.md) は早くそして効率的にgit repository を FTP 経由で公開してくれる優れもの、だそうです。

## 行なった際の環境
macOS High Sierra ver 10.13.5
Python 2.7.15 ＊1
git 2.15.2

＊1 3系で試してたら動かなかった

なお、本記事では、もろもろの必要なツールは [homebrew](https://brew.sh/index_ja.html) で install しています。

# 手順
mac であれば git と Python はデフォルトで入っていていると思います。
それが利用できるようであればその手順はスキップして頂いて良いです。

## git を install
git が入っている人はスキップ。

mac なら system の git 入ってると思うので問題ないと思いますが
なんとなく流れ的に homebrew でいれました。

以下コマンドでバージョンを確認

```
$ git --version
```

macならおそらく system の git が利用されていてその version が返ってくる。

以下は homebrew での install

```
$ brew install git
```

### homebrew でいれた git に path を通す

`~/.bash_profile` に以下の１文を追記。

```
export PATH="/usr/local/Cellar/git/2.5.0/bin:$PATH"
```

書き込んだら変更を読み込むために以下を実行

```
source ~/.bash_profile
```

以下のコマンドを打ってバージョンを確認しておく

```
$ git --version
```


## Python をインストールする
Python が入っている人はスキップ。

以下コマンドでバージョンを確認

```
$ python --version
```

mac だとデフォルトで入っているようですが、( おそらく `system` のバージョンが返ってくる )
今後書くかもわからないのでバージョン管理ツール( pyenv )でインストールすることにしました。

### まず Python のバージョン管理ツール pyenv を install

homebrew で install します。

```
$ brew install pyenv
```

### homebrew でいれた pyenv にパスを通す
`.bash_profile` を編集してパスを通す

```
export PATH="$PYENV_ROOT/bin:$PATH"
export PYENV_ROOT="$HOME/.pyenv"
eval "$(pyenv init -)"
```

書き込んだら変更を読み込むために以下を実行

```
$ source ~/.bash_profile
```

### pyenv を使って Python を install

インストールできるバージョンを確認してみましょう。

```
$ pyenv install --list
```

で install 可能なバージョンが確認できます。

~~私は `3.7.0` にしたので以下のように version を指定して install します~~

~~$ pyenv install 3.7.0~~

※ `3.7.0` だと動かなかったので 2系の最新を入れることにした。

```
$ pyenv install 2.7.15
```

### install したら 利用するバージョンを指定します
pyenv で入れている切り替え可能なバージョンを確認します

```
$ pyenv versions
```

以下のように返ってきました。

```
* system (set by /Users/ユーザー/.pyenv/version)
  2.7.15
  3.7.0
```


global で利用したければ `$ pyenv global 2.7.15`
local の利用にしたければ `$ pyenv local 2.7.15`
を打ちましょう。

```
$ pyenv global 2.7.15
```

以下のコマンドで指定したバージョンに切り替わっているか確認しましょう

```
$ python --version
```

## GitPython を install
Python もはいったところでようやく GitPython を入れます。

```
$ pip install gitpython
```

※ pip は Python のパッケージ管理ツールとのこと


## git-ftp.py を local にダウンロードしてくる

今回の記事のキモです。

github にソースが公開されているので local のお好みの場所に clone してくる

```
$ cd お好みの場所
$ git clone https://github.com/ezyang/git-ftp.git
```

そしてこれが実行できるようにパーミッションも変えておきましょう

```
$ chmod +x お好みの場所/git-ftp/git-ftp.py
```

## レポジトリに設定ファイル ( ftpdata ) を置く
__git 管理しているリポジトリフォルダの中__ に `.git/ftpdata` でファイルを作成。
中には以下の内容を記述。

なお、 [master] や [staging] は branch 名と関係していて、
そのブランチで push されたら __それぞれの設定したサーバーへ__ FTPをしてくれる仕組み
ssl の yes は Python 2.7 以降で使える模様(試してはない)

```ini
[master]
username=FTPのユーザー名
password=FTPのパスワード
hostname=FTPのホスト
remotepath=/htdocs/などなど
ssl=yes

[staging]
username=FTPのユーザー名
password=FTPのパスワード
hostname=FTPのホスト
remotepath=/htdocs/staging/などなど
ssl=no
```

それぞれ設定することで違うサーバーへFTPされるようにできますね。

<!--
post-receive がどうも成功しないようなので一旦コメントアウトしておく

## `.git/hooks` 配下にシンボリックリンクをはって git-ftp.pyを実行できるようにする


```
ln -s /Users/ユーザー名/お好みの場所/git-ftp/post-receive リポジトリのフォルダ/.git/hooks/post-receive
```

-->

## post-commit をつくって git-ftp.pyを実行できるようにする

`リポジトリのフォルダ/.git/hooks/post-commit`
のファイルを作って以下を記述。
pathは clone してきたところへ

```
#!/bin/sh

お好みの場所/git-ftp/git-ftp.py
```

そしてこれが実行できるようにパーミッションも変えておきましょう

```
$ chmod +x リポジトリのフォルダ/.git/hooks/post-commit
```

### tips
通常、開発は `feature/no1` など feature ブランチを切って開発することになると想定されます。
その場合は `staging` に `merge` されたタイミングでFTPされるのも必要になるとおもうので
`post-commit` と同様の内容で `リポジトリのフォルダ/.git/hooks/post-merge` もおいて置くと良さそう。


## サーバーに git-rev.txt のファイルを配置する
__これがリモートサーバーにないと push するたび毎回全ファイルアップしてしまう__ みたいです。

中身は最新コミットのハッシュを一文書いてください。
その記述された最新コミットのハッシュと次の push 時にコミットとの
差分のあるファイルのみをアップロードしてくれます。

`git-rev.txt` の配置場所ですが
レポジトリに設定ファイル `.git/ftpdata` の中
`remotepath` で書いたディレクトリに それぞれ ( [master] / [staging] )
にこのファイルをアップしましょう。

※ [master] / [staging] でハッシュが異なる場合はそれぞれのハッシュを書きましょう。

## push してみましょう

リポジトリ内でファイル編集、コミットしてpushしてみます。
ここからは git のコマンドです。

ファイルを編集してコミットします。

チェックアウトします。

```
$ git checkout -b staging
```

ファイルを編集してコミットします

```
$ git commit -a -m 'コミットメッセージ'
```

すると、このコミットする時に `git-ftp.py` が呼び出されてFTPを行ってくれています！

```
INFO: Using .git/ftpdata
INFO: Base directory is /htdocs/staging/などなど
INFO: Uploading 更新したファイル1
INFO: Uploading 更新したファイル2
```

更新されているか staging 環境をブラウザで確認してみましょう。


## 参考にさせていただいたページ
[Using GIT FTP and GIT Python](http://www.richardkotze.com/top-tips/using-git-ftp-and-git-python)
[CentOS6.4にGitlab入れて、さらにpushされたらftpでデプロイ出来るようにした話 - Pastalablog in はてな](http://pastak.hatenablog.com/entry/2013/12/01/190240)
[Karappo web design room » git-ftp.pyを使ってGitで管理しているFTP経由でローカルとリモートのファイルを同期](http://labs.karappo.net/index.php?itemid=301)
[git で push したファイルを FTP 経由で差分アップロードするよ - ヤルキデナイズドだった](http://d.hatena.ne.jp/uasi/20091024/1256322715)
[GitPythonを使う - Qiita](https://qiita.com/TakesxiSximada/items/ea778bb98b8c057ffd07)
[gitpython つかってみた - 俺は面倒が嫌いなんだ](http://rane.hatenablog.com/entry/2015/06/18/203339)