シェルでGit操作コマンドを作ったんだけど便利だから魅力を伝えたい~シェルの魅力も添えて~

こんにちは。謎の集団zeneloのアドベントカレンダー21日目です。今回はエンジニア歴・社会人歴共に2年目の私が、ちょっと前にシェルにはまりGit操作コマンドを作った話をしようと思います。

作ったものはこちら👉 [github-convs](https://github.com/natsumisawa/github-convs) 
diffみてaddしてcommitして〜等のあるあるGit操作が一発で楽にできたり、見たいPRをすぐにパッと開けたりします。（現在もアップデート中）
github-convsを作り始めた経緯から、github-covsの魅力、そしてついでに私の思うシェルの魅力までお伝えできたらいいなと思います。

## シェルとの馴れ初め編 ~github-convsを作り始めたきっかけ~

ある日、謎の集団zeneloの先輩（今やgithub-convsロイヤルカスタマー）がAWS CLIのコマンドを組み合わせてシェルコマンドを作成してきました。私がめんどくさいな〜と思っていた作業を、一発でできるようにするものでした。

linux勉強中だったこともあり、そのコードを解読し（読まされ）まんまとシェルに興味を持ちました。これ、アイディア次第で日々の生産性上げられるじゃん…！と、気づいたのもその時。

そんな中ちょうど、（GUIを卒業して）gitコマンドを利用するようになり、「毎回同じコマンド打つのめんどくさい、楽にしたい」という省エネ思考が働き、「GitHubのコマンドを組み合わせてシェルを書いてみようかな〜😊」と思い立ちました。

まずは、覚えたてのシェルコマンドで **欲しい差分だけをよしなにaddしてcommitまでする** コマンドを以下の2パターンで作ってみたのがgithub-convsの始まりでした。

- 差分ごとにaddしてcommitするコマンド
- ファイルごとにaddしてcommitするコマンド

![git-add-cmt-prt.gif](https://qiita-image-store.s3.amazonaws.com/0/137322/cf65b22c-f4c0-d322-7f04-39d2a20f1bf1.gif)

コマンドによってちょっと絵文字を添えてるのもこだわりポイント。このコマンドを使うようになっただけで、なんだかaddとcommitが楽しくなりました。笑

また、謎の集団zeneloで扱うリポジトリには大量のブランチが存在しており、**pullするブランチを選択するのが非常に辛い**という問題もありました。pull対象ブランチの選択ミスで何度か問題が起きたくらいには多いです。

ですが、本来pullすべきは**checkout元のブランチか現在のブランチ**のみなはず。

なので、`git-pll`というコマンドを作り、pullすべきブランチからしかpullできない仕様を実現しました。

![git-pll.gif](https://qiita-image-store.s3.amazonaws.com/0/137322/3a85aa75-60b0-dae3-8ae3-a5c667d9e2dc.gif)

すぐに欲しいものが形になって、すぐに使えるシェル、たのしい。これぞものづくりですね。

## シェルで生産性を上げ始めた編
GitコマンドでCUI操作をするようになってから、 **同じような作業を同じような順序** でするの面倒くさいし無駄だな〜😇と本気で思うようになりました。（毎回カーソルキーの↑を連打していることを含めて）

例えば、以下の作業です。

ブランチAにいるとする
1. `git checkout ベースとなるブランチ`
2. `git pull`
3. `git checkout -b ブランチB`

しかも、1を忘れてうっかりブランチAから*checkout*してしまうと、ブランチBを削除して作り直さないといけないので非常に面倒です。

なので、**`git-che`というコマンドひとつで、楽に安全に新しいブランチを作成**できるようにしました！

ユーザーは`git-che`コマンドを打ち、求められることに答えるだけ👇

1. create branchを選択
2. master/develop/現在のブランチからベースとなるブランチを選択
3. 新しいブランチ名を入力

2の操作にあるようにベースブランチを選択させることによって、上記のようなうっかり事故は起こりえません！（**ここ推しポイント**）

![git-che.gif](https://qiita-image-store.s3.amazonaws.com/0/137322/34100f34-5f3b-9ba5-79d5-dc9a9cc2def9.gif)

### ここでちょっと実装の話
シェルで大したコードは書いていません。**以下のような処理をパイプで繋げていくだけ**です。

- Gitコマンドからデータを取得する
- データをユーザーに見せられる形に加工する
- 加工したデータをfzf（インクリメンタルサーチコマンド）に食べさせる
    - （ユーザーはデータを選択する）
- 選択されたデータを元にGitコマンドをたたく

イメージ👇  `git-che` の2の処理です。

```shell
CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
BASE_BRANCH=$(echo "develop\nmaster\n$CURRENT_BRANCH" | uniq | fzf --prompt="BASE_BRANCH > ")
```

そしてこれはまさに、UNIX哲学！
> ひとつでうまくやろうとするな ひとつの得意を組み合わせろ これがUNIXの哲学である。

（そこに、しびれる！憧れる！）

`grep`/`awk`/`sed`のような基本コマンドと、それを組み合わせていくアイディア次第で、作りたいものをほとんど実現できます。それはまるでパズルを解いているような感覚で、時間を忘れて書いてしまいます。その考え方は、私のものづくりの理想そのものでした。

## ユーザーからの要望がgithub-convsと私を成長させた編

github-convs誕生当初から成長を見てくれて、便利さに気付き始めたロイヤルカスタマーから、ついに要望がありました。「**PRを探すの面倒だからすぐ開けるようにして欲しい！**」と。私自身も時々めんどくささを感じていて、めちゃくちゃ共感でした。

ということで、`git-opn-pr-crnt`という魔法コマンドでひとっとび！
<img width="687" alt="名称未設定 25 P1.png" src="https://qiita-image-store.s3.amazonaws.com/0/137322/0068ad48-66fe-1c7f-e9d3-69a3e74bfbd1.png">

ひっととびの様子👇
![git-opn-pr-crnt (1).gif](https://qiita-image-store.s3.amazonaws.com/0/137322/287bb627-fbce-e25b-09ad-b678aff673f4.gif)

これにはロイヤルカスタマーもにっこり。

実際まじで便利です。（ここだけはsource treeに勝ったと言いたい、ここだけは）

また、現在のブランチのPRを開くだけでなく、インクリメンタルサーチで選択したブランチのPRをすぐ開けるコマンドも作りました。なので、ターミナルさえ開いていれば、「あ、そのPRですね、これです〜（サッ）」というように、どんなPRもすぐ出してくれる人になることができます。

### ここでちょっと実装の話

コマンドの中身をちらっと紹介すると、こんな感じです👇
PR情報を取得できるgithubのAPIを叩くために、ごにょごにょしています。

```shell
API_URL="https://api.github.com/repos/${OWNER_AND_REPO}/pulls?head=label:${OWNER}:${BRANCH}"
PR_NUMBER=$(curl -u :$GIT_TOKEN $API_URL | jq '.[] | .url, .head.ref' | sed -e "N;s/\n/,/g" | awk -F, '{print $1}' | awk -F/ '{print awk $NF}' | tr -d '\"')
    if [ -n "$PR_NUMBER" ]; then
      open -a Google\ Chrome "https://github.com/${OWNER_AND_REPO}/pull/${PR_NUMBER}"
...
```

ユーザーが喜んでくれるなら・・・なんでもします！という精神でシェルを書いていたら、こんなコマンド使いもできるようになりました。
`git-che`と比べると、ちょっと高度なことをしているように見えますね・・・しみじみ。

## おわりに
最後まで読んでくださり、ありがとうございます。今までCUIに苦手意識を持っていましたが、シェルに出会い、その魅力に惹かれ、ユーザーの要望を実現するためにgithub-convsも私も成長していきました。開発の効率を上げられるシェルという新しい武器を手に、より良いものを作っていけるよう、今後も精進していきます！