退屈なgit commitの定型文はGitフックにやらせよう

現在働いている会社では、チケットを立ててタスク管理をしています。
そのためgitの運用、というかブランチの命名規則として下記のように「タスク種別/チケット名」というのがあります。
例：fix/PRJ-123

そして、後で問題が見つかった時などにどのチケットに伴う作業だったのかが分かるように、コミットメッセージの先頭にチケット名を明記するようになっています。
例：refs PRJ-123, *コミットメッセージ*

でも、これって正直いちいち書くのが面倒です。笑
毎回`git status`とか`git branch`とかしてブランチ名をコピペしたりして……

**こういうのは自動化させちゃいましょう！！**

# Gitフックを利用する
gitには、特定のアクションが発生した時にカスタムスクリプトを叩く方法があります。　
それがGitフックです。
詳しくは[こちらのドキュメント](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF)をご覧ください。

## 自作のスクリプトを読み込む設定をする
まずは、自作のスクリプトを読み込むために、`.git_template/hooks/`ディレクトリを用意しましょう。

```
$ mkdir -p  ~/.git_template/hooks
```
次に、gitの方でこのディレクトリを読み込めるように設定させます。

```
$ git config --global init.templatedir '~/.git_template'
```

## スクリプトの作成
ここまでおこなったら、スクリプトを作成していきます。
今回は、コミットメッセージエディターが起動する直前、デフォルトメッセージが生成された直後に実行されるprepare-commit-msgフックを作成していきます。

```
$ touch ~/.git_template/hooks/prepare-commit-msg
```
これ以外にも色々と種類があるので、確認してみると面白いと思います。

```
$ cd /path/to/your/project/.git/hooks
$ ls
applypatch-msg.sample  post-update.sample     pre-commit.sample  pre-rebase.sample   update.sample
commit-msg.sample      pre-applypatch.sample  pre-push.sample    pre-receive.sample  prepare-commit-msg.sample
```

スクリプトの中身は、以下のような感じにしました。
*Macを使用する人は、下記スクリプトではsedコマンドが意図しない挙動を見せるので、[こちらのQiitaの記事を合わせてご覧ください。](https://qiita.com/hiroaki510/items/5b1309c52bf098cbc928)*

```bash
#! /bin/bash

#Macを使う人は、gnu-sedをインストールしてからエイリアスを設定して、
#下記2行のコメントアウトを外してください！
#shopt -s expand_aliases
#source ~/.bashrc

branchName=$(git rev-parse --abbrev-ref HEAD)  # 現在のブランチ名を返す
ticketName=$(echo $branchName | cut -d "/" -f 2)  # コミットメッセージに必要なチケット名の抽出
firstLine=$(head -n1 $1)  # git commit --amendとの区別のために最初の一行を取得

if [ -z "$firstLine" ] ;then  # 一行目が空行であれば（--amendでなければ）以下を実行
	sed -i "1s/^/refs ${ticketName},/" $1  # 最初の一行の先頭を「refs チケット名,」に書き換える
fi
```
補足として、`head -n1 $1`は何のファイルを引数にしているのかパッと見分かりにくいのですが、`git commit`のデフォルトメッセージです。
>prepare-commit-msgフックは、コミットメッセージエディターが起動する直前、デフォルトメッセージが生成された直後に実行されます。 このフックでは、デフォルトメッセージを、コミットの作者の目に触れる前に編集できます。 
*--[公式ドキュメント](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF)より*

### もしもサンプルスクリプトが生成されない場合
先に自作スクリプトを生成してしまうと、サンプルスクリプトが生成されません。
こういう時は一旦、`init.templatedir`をunsetして下記のように進めてみてください。

```
$ git config --global --unset init.templatedir
# vimを開いて[init]を念のため消す
$ vim ~/.gitconfig
$ git init
$ git config --global init.templatedir '~/.git_template'
```


## スクリプトに実行権限を付与
スクリプトの作成が終わったら、実行権限を付与してください。

```
$ sudo chmod a+x ~/.git_template/hooks/prepare-commit-msg
```

## リポジトリにてスクリプトの生成
最後に、作業が必要なリポジトリへ移動してスクリプトを生成してください。
`git init`をするだけです。

```bash
$ cd /path/to/your/project/
$ git init
$ cd .git/hooks/
$ ls | grep prepare-commit-msg
prepare-commit-msg  # 自作のフックスクリプトが生成されている事の確認
prepare-commit-msg.sample
```

# コミットメッセージが自動生成されているか確認！
ここまで進めたら、実際にコミットメッセージが自動で生成されているのか確認してみましょう！

```bash
$ cd /path/to/your/project/
$ git branch
  develop
* fix/PRJ-123
$ vim test.txt  # テストファイルの作成
$ git status
On branch fix/PRJ-123
Your branch is up-to-date with 'origin/fix/PRJ-123'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	test.txt

nothing added to commit but untracked files present (use "git add" to track)
$ git add test.txt
$ git commit  # vimのエディタへ

refs PRJ-123,
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch fix/PRJ-123
# Your branch is up-to-date with 'origin/fix/PRJ-123'.
#
# Changes to be committed:
#»------new file:   test.txt
#
```
無事に自動生成を確認出来ました！
やったね！

## もし間違えてgit commitを打っちゃったら…
ちなみに、もしも間違えて`git commit`をしてしまったら、最初の一行目（ここで言うと「refs PRJ-123,」のこと）をまるっと削除してから`:wq`で保存してエディタを終了させれば`git commit`を打つ前に戻ります。

# 追記
## 2019/01/07 エイリアスも対応
上記は`git commit`に対してでしたが、`git push`の際も現在のブランチ名をコピペしないで出来るようにエイリアスを設定しました。

```:~/.gitconfig
[alias]
cb="git rev-parse --abbrev-ref HEAD"  # Current Branchの意
```

設定後のコマンドの入力は以下のようにします。
`git push origin ${cb}`
これでマウスorトラックパッドを使わずに`git commit`と`git push`が出来るようになりました！