gitリポジトリのマージ済みで古いブランチをいっきに消す

### 注意
ここで紹介するスクリプトの実行は各自の責任でお願いします。

## モチベーション
プロジェクトでプルリクエストのブランチは溜まりがち。気がつくと数ヶ月分とか。
だいたいのgit hostのweb UIではちまちま消さなきゃいけない。ひとつずつ。

…… め ん ど い！！ザックリ選んでガサッと消したい！！

## `git delete-merged-branches`
[スクリプト(gist)](https://gist.github.com/kikuchi-m/55028305055a3637d1ab711cece988f9)にしました。
interactiveに

* どのリモートのブランチで
* どのブランチにマージ済みで
* 最終コミット(ブランチのhead)がいつより古いか

を指定していっきにブランチをクリーンします。ローカルのブランチも古ければクリーン対象になります。
(繰り返しになりますが、冒頭にも書いた通り実行は自己責任で。)

### 前提
* bash
* git

### セットアップ
1. 上のスクリプトをダウンロード
1. PATHの通った場所に置く
1. 実行権限付与 (`chmod +x`)

### 実行
任意のリポジトリのディレクトリに移動し、`git delete-merged-branches`を実行すると条件を聞かれます。
以下は入力値がデフォルトのまま(指定なし)の実行例。

* `origin`にある
* `origin/master`にマージ済みの
* 最終コミットが4ヶ月以上前の

ブランチをクリーンします。

```
$ cd wok/my/awesome/product
$ git delete-merged-branches
remote (origin):
base (origin/master):
older than (4 months ago):
deleting: 36d0389 2020-02-01 ... (origin/feature/foo) ...  # 省略 time, committer, subject)
deleting: 02237d9 2020-02-19 ... (origin/feature/bar) ...
deleting: 3d6c833 2020-03-05 ... (origin/feature/baz) ...
deleting: 79d8e5a 2020-03-09 ... (work/some) ...  # ローカルブランチ
deleting: 41df532 2020-03-28 ... ...
remaining: 176e94c 2020-04-03 ... ...
remaining: 17f115a 2020-04-11 ... ...
...
...
continue? (yes/No): yes
continue...
To ... (remote URL)
 - [deleted]    feature/foo
To ...
 - [deleted]    feature/bar
To ...
 - [deleted]    feature/baz
...
```

まずリモートを指定します。デフォルトは`origin`。

```
remote (origin):
```

複数のリモートをトラッキングしていて、消したいブランチが`mirror`上にある場合は

```
remote (origin): mirror
```

と入力し、実行(enter)します。
次にクリーンしたいブランチが**どのブランチにマージ済みか**(ベースブランチ)を指定します。(←ここ重要) 
デフォルトは`origin/master`。リモート名も含めて指定します。

```
base (origin/master):
```

developブランチにマージ済みのブランチをクリーンしたい場合は`origin/develop`と入力します。

```
base (origin/master): origin/develop
```

最後にいつより古いブランチをクリーンするか指定します。デフォルトは`4 months ago`。

```
older than (4 months ago):
```

remote、base同様に任意に指定できます。指定する日時は相対、絶対いずれも指定可能です。詳しくは`git log`コマンドの`--since`、`--after`オプションを調べてみてください。

```
older than (4 months ago): 2 weeks ago
```

```
older than (4 months ago): 2020-04-01
```

条件の指定が終わるとbaseにマージ済みの(baseを除く)ブランチが時刻昇順で一覧され、指定した日時より古いものは`deleting:`、新しいものは`remaining:`と表示されます。
下の例ではリモートの`feature/baz`とローカルの`some`はクリーン対象、リモートの`feature/hoge`とローカルの`tweak`は対象外となります。

```
deleting: 3d6c833 2020-03-05 ... (origin/feature/baz) ...
deleting: 79d8e5a 2020-03-09 ... (some) ...
remaining: 176e94c 2020-04-03 ... (origin/feature/hoge) ...
remaining: 17f115a 2020-04-11 ... (tweak) ...
```

最後に本当に実行を継続するか確認があります。ここで`yes`と指定でブランチのクリーンを行います。デフォルトでは`no`となっているので未入力のままenterでなにもせず終了します。

```
continue? (yes/No): # 入力待ち。引き返すならここが最後。
```

### オプション
interactiveに実行せず、オプションを引数で指定できます。

* `--remote` `-r`: リモート
* `--base` `-b`: マージベースブランチ
* `--older-than` `-s`: 基準日時(いつより古いか)
    * `"`を忘れないように (`--older-than "1 month ago"`)
* `--yes`: 指定すると最後のyes/noなしでクリーン実行

他

* `--dry-run` `-n`: ブランチの一覧までで終了(クリーンを実行しない)
* `--local-only`: 条件にマッチするローカルのブランチのみクリーン

## 捕捉
* どんな指定をしてもremoteの`master`ブランチは常にクリーンの対象外です。
* コミットの時刻比較(older than)には`committerdate`が使われます。`auhordate`ではありません。
* どのブランチにもマージされていない(合流していない)ブランチは、このスクリプトでは消せません。手動で消してください。
* 説明上「ベースブランチを指定」と書きましたが、\<commit\>で指定可能です。commit hash、tag、`HEAD`、`HEAD~10`など。

---
#### Note
「クリーンの対象期間にあるけど消したくない」といったブランチを除くオプションをつけようかどうしようか。`--exclude <pattern>`とか。
ローカルを対象外にするオプションをつけようかどうか。`--remote-only`とか。(ローカルにブランチを作らないからなぁ……。)