git diff を読みやすくする配色を考える

ターミナル上で git diff を見るときにどうしても色数が絞られてしまい、もう少し読みやすい配色にできないものか考えてみました。

## tl;dr

```ini:~/.gitconfig
[color "diff"]
  meta = 242 238
  frag = 239 236
  old = 167 normal
  new = 030 normal
  context = 240
  commit = 246 024

[diff]
  compactionHeuristic = true

[pager]
  log = diff-highlight | less
  show = diff-highlight | less
  diff = diff-highlight | less
```

* `diff-highlight` について
    * [Git2.9のキレイなdiffを出すためのconfig - Qiita](http://qiita.com/takyam/items/d6afacc7934de9b0e85e)
* `compactionHeuristic` について
    * [Git 2.9 has been released](https://github.com/blog/2188-git-2-9-has-been-released)


iTerm2 で背景色を `#002833` に設定している自前の環境だと次のような見栄えになります。

![image](https://qiita-image-store.s3.amazonaws.com/0/3189/350a6e0b-aae6-93ef-7c8c-b170e46f8a16.png)

iTerm2 のデフォルトカラースキームだと次のような見栄えになります。

![image](https://qiita-image-store.s3.amazonaws.com/0/3189/7d505e1a-5ed7-8122-56fb-2b9561473982.png)

## Git は1677万色が扱える

「さすがに256色は対応してるだろう」と思って調べてみたところ、256色どころか 24-bit True Color (1677万色) に 2014 年末の段階で対応していたようです。[^git-true-color]

[^git-true-color]: [parse_color: support 24-bit RGB values · git/git@17a4be2](https://github.com/git/git/commit/17a4be26060b00a867cbe54ee906fe03813470ec)

ターミナルアプリが True Color に対応していれば、 hex で色指定して有効化できます。

iTerm や mintty は True Color に対応しているようです。良いですね。

## 設定方法

git diff の色設定を [ドキュメント](https://git-scm.com/docs/git-config) から抜粋します。[^git-config-doc]

[^git-config-doc]: 詳細や最新の情報については [Git - git-config Documentation](https://git-scm.com/docs/git-config) を参照してください。


* `color.diff.<slot>`
  * `context`
      * context text - `plain` is a historical synonym
  * `meta`
      * metainformation
  * `frag`
      * hunk header, func (function in hunk header)
  * `old`
      * removed lines
  * `new`
      * added lines
  * `commit`
      * commit headers
  * `whitespace`
      * highlighting whitespace errors

これらの slot は実際の diff [^diff-example] を例にすると次のようになります。

[^diff-example]:  [facebook/react](https://github.com/facebook/react) `git diff 681c68c cc41ec2`

```diff:meta
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 8c2f98b..c0a9cfd 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
```
```diff:frag
@@ -1,6 +1,6 @@
```
```diff:context
 {
   "name": "react-build",
```
```diff:old
-  "version": "15.3.1",
```
```diff:new
+  "version": "15.3.1-rc.2",
```
```diff:context
   "dependencies": {
     "art": {
       "version": "0.10.1",
```

`commit` は `git diff` では登場せず、 `git log` や `git show` したときのコミットハッシュの部分が該当します。


### 色の指定方法

`${slot} = ${foreground} ${background} ${attribute}` のように指定します。

詳しくは [Git - git-config Documentation](https://git-scm.com/docs/git-config) の Values - color の項目を参照してください。

```ini:example
[color "diff"]
meta = white black normal // 16色
meta = white              // 省略可
meta = 015 000 normal     // 256色
meta = "#ffffff" "#000000" normal // True Colors
```

256 の各色の番号の確認は [Xterm 256color mode color chart, organised into sections.](https://gist.github.com/jasonm23/2868981) あたりが便利です。

hex で指定する場合は `""` が必要です。

## 配色を考えるときに考えること

* 最も興味がある部分
    * 有彩色で意味や役割を与える
    * コントラストを高めにする
        * 最初に目に入るようにするため
    * 線より面のほうが視覚的インパクトが強まるので、必要に応じて面の塗りを利用する
* 次に興味がある部分
    * コントラストを下げる
        * 最初に目に入ると、最も興味がある部分が目立ちにくくごちゃごちゃして感じる
        * 読みたいときに少し注視すれば読めるレベルに抑える
    * 無彩色に近い配色でも役割を果たせるのであればそうしていく

興味のある順序で優先順位を付けていくとだいたい次のようになるので、この順番で目に入るよう色調整してみました。

1. `new`, `old`
  * どんな変更がなされたか
2. `meta`
  * どのファイルが変更されたのか
3. `frag`
  * 変更位置の情報
4. `context`
  * 補足情報

## あとがき

せっかく True Colors が使えるので自分の iTerm のカラースキームにびったり合う色を指定することもできるんだけど、
じゃあ iTerm のカラースキームを切り替えることがあったら gitconfig の色設定も書き換えねばならないのか？と思うと、さすがに面倒だったので、 結局 256 色の中から選ぶことにしました。

256 色程度だと使いたい色が意外とないなと思いました。

本当は完全な無彩色というのはあんまり使いたくなく、ほぼ灰色に見えるけどちょっと色味がある色とかにすると、より自然に馴染む感じになると思う。

gitconfig では `[include]` で別ファイルを読み込む機能があるので、カラースキームだけ切り分けて、iTerm のテーマと同期させるということもがんばればできるかもしれないですが、今回はやってないです。

追記:
そういえばターミナルの配色をいじるときは、このサイトがなかなか便利でした。

* [terminal.sexy - Terminal Color Scheme Designer](http://terminal.sexy/)