開発現場で使うgitコマンドを実行するシェルスクリプトを作ってみた

PHPer会議でシェルスクリプトを使ってブランチ管理を自動化している発表があり、触発されて作ってみました!

私の開発チームのブランチ管理手法としては、、、
・毎週一定の曜日にリリースを行う
・リリース年月日を接頭辞につけたリリースブランチ(`yyyymmdd-release`)を作る
・リリースブランチから結合テスト環境へ次週リリースする開発を反映する用のブランチ(`yyyymmdd-develop`)を切り出す
・開発中のブランチにリリースブランチをpullする(コンフリクトさえなければ問題ないが、デグレリリーストラブルが起こったことがあり、防止策として)

### 作成したシェル

```shell:git.sh
#!/bin/bash

# 内容1
ESC=$(printf '\033')
# 31m ~ 36m RED/GREEN/YELLOW/BLUE/MAGENDA/CYAN
PREFIX=$(date -j -v+1w +"%Y%m%d")
CURRENT=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
CURRENT_BRANCH=${CURRENT:2}
STASHED=0

# 内容2
confirm() {
  printf "${ESC}[33m%s${ESC}[m\n" "Next release day is $PREFIX (Y/N)?"
  while read -r -n 1 -s answer; do
    if [[ $answer = [YyNn] ]]; then
      [[ $answer = [Yy] ]] && retval=0
      [[ $answer = [Nn] ]] && retval=1
      break
    fi
  done
  echo # just a final linefeed, optics...
  return $retval
}

stash_confirm() {
  echo "If you have any filechanges on current branch, should git stash."
  printf "${ESC}[33m%s${ESC}[m\n" "Execute git stash (Y/N)?"
  while read -r -n 1 -s answer; do
    if [[ $answer = [YyNn] ]]; then
      [[ $answer = [Yy] ]] && retval=0
      [[ $answer = [Nn] ]] && retval=1
      break
    fi
  done
  echo # just a final linefeed, optics...
  return $retval
}

return_confirm() {
  printf "${ESC}[33m%s${ESC}[m\n" "Do you want return $CURRENT (Y/N)?"
  while read -r -n 1 -s answer; do
    if [[ $answer = [YyNn] ]]; then
      [[ $answer = [Yy] ]] && retval=0
      [[ $answer = [Nn] ]] && retval=1
      break
    fi
  done
  echo # just a final linefeed, optics...
  return $retval
}

# 内容3
if [[ -n $1 && "x$1" != "x$PREFIX" ]]; then
  PREFIX=$1
  echo "Received your input >> $PREFIX"
fi

RELEASE="$PREFIX-release"
DEVELOP="$PREFIX-develop"

# 内容4
if confirm; then
  printf "${ESC}[32m%s${ESC}[m\n" "OK, lets prepare next release!"
  if stash_confirm; then
    git stash save "stash of $CURRENT"
    STASHED=1
  fi
  # Checkout and update master branch
  git checkout master
  git pull origin master
  # Make release brach and push
  git checkout -b $RELEASE
  git push origin $RELEASE
  # Make develop brach and push
  git checkout -b $DEVELOP
  git push origin $DEVELOP
  # 内容5
  if return_confirm; then
    git checkout $CURRENT
    if  [ $STASHED ]; then
      printf "${ESC}[32m%s${ESC}[m\n" "Applying from stash of $CURRENT "
      git stash apply stash@{0}
    fi
    printf "${ESC}[32m%s${ESC}[m\n" "Now on <$CURRENT>. good bye!"
  else
    printf "${ESC}[34m%s${ESC}[m\n" "OK, You are stay on <master> branch."
  fi
else
  echo "Stop processing..."
fi
```

#### 内容の解説

1. 変数定義・・・リリースは基本1週間毎なので、1週間後の日付を変数にデフォルト値で定義
2. 関数定義・・・シェルスクリプトでは関数定義を関数呼び出しの前に行う必要があるため、定義。 
3. 変数代入・定義・・・シェル実行時にコマンド引数として次回リリース日を打てるようにした。コマンド引数があった場合、`PREFIX`に代入する。`PREFIX`に依存する変数も、この処理の後に定義。

4. interactive処理・・・ブランチ名の間違い、現在いるブランチの変更のstashなど、間違いになりそうな事項については確認した上で処理を実行する
5. 元いたブランチへの復帰・・・一連の処理が完了したら、元いたブランチへ戻るかも選択できる。stashを実行していて元いたブランチへ戻る場合、ブランチへ戻った後にapplyも実行する

### 資料
[dateコマンドの使い方](https://zenn.dev/skksky_tech/articles/20201115_date-command#date%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9) (dateコマンドの使い方一通り)

[Macのdateコマンドで1日後の日付を取得する](https://salumarine.com/get-the-next-day-using-date-command-on-mac/) (Macターミナルで`--date`オプションが使えないのの解決)

[シェルスクリプトのechoで”問題なく”色をつける(bash他対応)](https://qiita.com/ko1nksm/items/095bdb8f0eca6d327233) (CLIに色をつける)

[Bashの便利な構文だがよく忘れてしまうものの備忘録](https://qiita.com/Ping/items/57fd75465dfada76e633) (Yes/Noの条件分岐処理)

[現在のgitブランチの名前をシェルスクリプトの変数に取得する方法](https://www.javaer101.com/ja/article/3076040.html)

[プログラマーの君！ 騙されるな！ シェルスクリプトはそう書いちゃ駄目だ！！ という話](https://salumarine.com/get-the-next-day-using-date-command-on-mac/)

### 感想
面倒なブランチ管理操作が一瞬で終わるようになりました。
シェルの構文の理解が追いつかず、冗長な書き方が残っているのは要改善ですが、インタラクティブな実装もできたのでひとまず満足です。

「gitコマンド程度、チーム開発ならできて当然。手早くできるようになれ!」というのはもっともですが、
「お決まりのgitコマンドなんて人がやらなくてもいい。単純作業はプログラムにやらせる!」の方がエンジニアらしいアプローチでいいですね!