git pushで上流ブランチがない場合の自動作成に一度確認を挟みたい

思い通りにいかなかった。

やりたいこと

git pushを実行した際に上流ブランチがないと下記のエラーが発生します。

fatal: The current branch feature/hogehoge has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin feature/hogehoge

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.

上記のエラーを確認してから打ち直すのが面倒なので、自動化をしようと試みました。メッセージに従って

git config --global --add --bool push.autoSetupRemote true

と実行すれば自動で上流ブランチの作成まで行なってくれる*1のですが、心理的に一度確認を挟んでから作成するようにしたいと考え、別の手段を検討しました。

pre-pushではできない

Git フックで上記を実現できないかなと思い、下記のようなスクリプトを(Copilotが)作成しました。

#!/bin/zsh
# 現在のブランチ名を取得
current_branch=$(git rev-parse --abbrev-ref HEAD)

# リモートブランチが存在するか確認
if git show-ref --verify --quiet refs/remotes/origin/$current_branch; then
  # リモートブランチが存在する場合、通常のpushを実行
  exit 0
else
  # リモートブランチが存在しない場合、ユーザーに確認
  echo "Remote branch does not exist. Do you want to create and push to it? (y/n)"
  read answer
  if [[ $answer =~ ^[Yy]$ ]]; then
    # ユーザーがyesを選択した場合、ブランチを作成してpush
    git push --set-upstream origin $current_branch
    exit 1
  fi
fi

しかし、上記のスクリプトは動きません。git pushを実行しても上記のスクリプトが実行される気配がありません。動かない原因はシンプルで、pre-pushがトリガーされていないためです。pre-pushのフックは実際に何かがプッシュされる前にトリガーされるため、リモートブランチが存在しない場合はgit pushは何も行わず、結果としてpre-pushもトリガーされないのです。

Gitのドキュメントにもそのように記載があります*2

pre-push フックは、 git push を実行した際、リモート参照が更新された後、オブジェクトの転送が始まる前に実行されます。

git-scm.com

カスタムコマンドを作るしかない

上記を解決するために、下記のカスタムコマンドを(Copilotが)作りました。

#!/bin/zsh

current_branch=$(git rev-parse --abbrev-ref HEAD)
remote_branch_exists=$(git ls-remote --heads origin $current_branch)

if [ -z "$remote_branch_exists" ]; then
    echo "Warning: The remote branch does not exist."
    echo "Would you like to create it? (y/n)"
    read answer
    case $answer in
        [yY]* ) git push --set-upstream origin $current_branch;;
        * ) echo "Aborting push."; exit 1;;
    esac
else
    git push
fi

こうすることでやりたいことが実現できましたが、Git フックで実現できないのは少しモヤモヤしますね。。git pushエイリアスでこのスクリプトを利用しようとは思わない(もちろんオプションも与えて実行できるようにする前提で)ですし、、

*1:git v2.37.0 からの機能のようです

*2:つまり、事前に読めばわかることでした