うっかり屋さんのためのgit stash

はじめに

この記事は、2019年10月04日に2019年10月04日にQiitaに投稿をした内容と同じものです。 GatsbyでこのWebサイトを開設した時に最初に投稿するネタがあまりにも無さすぎたので、自分のQiitaから既に書き上げてあるものからこちらのネタをPickUpしました。

CodeBlockが見辛いので、Qiitaの方を見たい方はこちらからどうぞ!

うっかりミスを技術で防止

僕は普段よくうっかりミスをします。 CLI上での時の流れは無慈悲なもので、エンター1つでけっこう面倒なことになったりします。 そんな無慈悲な時間を少しでも減らすために少し苦労をしてみましょう。

git stashを慎重に

git stashコマンド使ってますか? 僕はこのコマンドでよく痛い思いをしました。

git stash pop ←これを連続で打ってCONFLICT起こしたりもしました。とても面倒です。

ですので今回はgit stashをもっと対話的に実行しようということでShellでコマンドを自作しました。 普段はGoのcobraなどを使っているのでShellには馴染みがなかったので今回色々勉強になりました。

対話型コマンドのキーとなるread

うっかり屋さんはひとりで突っ走りがちですので、「〜だけど大丈夫?」みたいなワンクッションあると安心します。 それを実現するためにread構文を使って対話型のコマンドを実現できます。 例えば下は、stashしたブランチと現在いるブランチが違った時に確認をする処理です。

if [ $CURRENT_BRANCH != $TARGET_BRANCH ]; then
          echo "----------------------------------"
          echo "取り出そうとしているstashは現在のブランチの作業ではないです。取り出しますか?[y/N]"
          read IS_POP
          case $IS_POP in
              [yY])
                  echo "-------------------------------"
                  echo "選択したstashを残しますか? [y/N]"
                  read IS_REMAIN_STASH
                  case $IS_REMAIN_STASH in
                      [yY]) eval git stash apply ${TARGET_STASH%%:*};;
                      [nN]) eval git stash pop ${TARGET_STASH%%:*};;
                  esac
                  ;;
              [nN]) exit;;
          esac

read [変数名]でユーザからの入力を受け取り、その情報を元にcaseで分岐しています。

入力の手間を少しでも省いてタイポを防止する

うっかり屋さんは誰から見られているわけでもないのにすごく焦ります。 異常なほどタイポします。 ですので、例えば git stash save "hogehoge" と打つ場合は"とか高確率でタイポします。 そんなタイポを減らすために以下のような処理を書くことが出来ます。

if [ "$1" = "save" ]; then
      echo "-----------------------------"
      echo "Stash内容の説明を入力"
      read STASH_MESSAGE
  
      eval git stash save "$STASH_MESSAGE"

こんな感じで引数に何かを渡すだけでメッセージの部分を形成して良い感じのコマンドに直してくれる。 やっていることは大したことありませんが、かなと英字を頻繁に入れ替える必要もなくなるので少し便利です。

ソースコード

良かったら使ってみてください。

# git stashの短縮版
alias stash=stash-pop
function stash-pop() {
  if [ "$1" = "list" ]; then
      eval git stash list

  elif [ "$1" = "show" ]; then
      TARGET_STASH="$(git stash list | fzf)"
      eval git stash show -p ${TARGET_STASH%%:*}

  elif [ "$1" = "save" ]; then
      echo "-----------------------------"
      echo "Stash内容の説明を入力"
      read STASH_MESSAGE
  
      eval git stash save "$STASH_MESSAGE"

  elif [ "$1" = "pop" ]; then
      TARGET_STASH="$(git stash list | fzf)"
      CURRENT_BRANCH="$(git status --branch --porcelain | head -n 1 | sed 's/## //')"
      TARGET_BRANCH_STASHNUM=${TARGET_STASH%:*}
      TARGET_BRANCH=${TARGET_BRANCH_STASHNUM##* }
      if [ $CURRENT_BRANCH != $TARGET_BRANCH ]; then
          echo "----------------------------------"
          echo "取り出そうとしているstashは現在のブランチの作業ではないです。取り出しますか?[y/N]"
          read IS_POP
          case $IS_POP in
              [yY])
                  echo "-------------------------------"
                  echo "選択したstashを残しますか? [y/N]"
                  read IS_REMAIN_STASH
                  case $IS_REMAIN_STASH in
                      [yY]) eval git stash apply ${TARGET_STASH%%:*};;
                      [nN]) eval git stash pop ${TARGET_STASH%%:*};;
                  esac
                  ;;
              [nN]) exit;;
          esac
      else
          echo "-------------------------------"
          echo "選択したstashを残しますか? [y/N]"
          read IS_REMAIN_STASH
          case $IS_REMAIN_STASH in
              [yY]) eval git stash apply ${TARGET_STASH%%:*};;
              [nN]) eval git stash pop ${TARGET_STASH%%:*};;
          esac
      fi


  elif [ "$1" = "drop"]; then
      TARGET_STASH="$(git stash list | fzf)"
      REGEX="/(^.*)(?=: On)/"

      echo "-------------------------------"
      echo "選択したstashを削除します。よろしいですか?[y/N]"
      read IS_DELETE_STASH
      case $IS_DELETE_STASH in
          [yY]) eval git stash drop ${TARGET_STASH%%:*};;
          [nN]) exit;;
      esac
  fi
}