40
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめての記事投稿
Qiita Engineer Festa20242024年7月17日まで開催中!

誤ってpushしないためのbashrc

Last updated at Posted at 2024-06-30

はじめに

push、怖いですよね。
mainやdevelopにプッシュしてしまったら…と考えただけでストレスを感じます。
これでは精神衛生上良くないので、予防策を講じようと思います。

※bashと.bashrcの説明は省きます。
※例外は考慮していません。

追記

コメントを頂いて知ったのですが、一般的にはフック機能というものを使うらしいです。

リポジトリごとに設定できるのが良いですね。

筆者の環境

環境によっては動かないかもしれないので、私の環境を書いておきます。
Windows 11 Pro + WSL(Ubuntu 22.04.4 LTS)

手順

  1. git関数の追加
  2. ブランチの保護
  3. ブランチの保護を解除
  4. 保護されたブランチの一覧
  5. pushの制限

という流れでやっていきます。

1. git関数を追加

bashrc
git() {}

試しに、git pushでHello World!を出力してみます。

bashrc
git() {
  case $1 in
  "push")
    echo "Hello World!"
    ;;
  esac
}

実行してみます。

bash
~/hoge: bash

~/hoge: git push
Hello World!

動きました!
動作確認出来たので、pushの部分は削除しておきます。

bashrc
git() {
  case $1 in
- "push")
-   echo "Hello World!"
-   ;;
  esac
}

2. ブランチの保護

ブランチ名を直接条件に追加しても良いですが、
保護されたブランチが増えてくると管理が面倒です。
git protect ブランチ名で保護出来るようにします。

まず、保護したブランチを保存するためのファイルを作成します。
好きなディレクトリに作成してください。

bash
~/hoge: touch protected_branches.txt

次に、作成したファイルを読み込みます。

bashrc
protected_branches_file="/hoge/protected_branches.txt"

次に、保護するブランチをファイルに書き出します。

bashrc
protect_branches() {
  for arg in "$@"; do
	# 一致する行がない場合
	if ! grep -xq "$arg" "$protected_branches_file"; then
      echo "$arg" >> "$protected_branches_file"
	  echo "$arg を保護しました"
	else
	  echo "$arg は既に保護されています"
	fi
  done
}

最後に、git protect ブランチ名で保護できるようにします。

bashrc
git() {
  case $1 in
  "protect")
	shift
	protect_branches "$@"
    ;;
  esac
}

実行してみます。

bash
~/hoge: bash

~/hoge: git protect hoge fuga
hoge を保護しました
fuga を保護しました

~/hoge: git protect hoge fuga
hoge は既に保護されています
fuga は既に保護されています
protected_branches.txt
+ hoge
+ fuga

動きました!ファイルも更新されています!

3. ブランチの保護を解除

git protect -rm ブランチ名で解除出来るようにします。

まず、ファイルから保護を解除したいブランチを除けるようにします。

bashrc
unprotect_branches() {
  for arg in "$@"; do
	# 一致する行がある場合
	if grep -xq "$arg" "$protected_branches_file"; then
      # 行完全一致
	  sed -i "/^$arg$/d" "$protected_branches_file"
	  echo "$arg の保護を解除しました"
	else
	  echo "$arg は保護されていません"
	fi
  done
}

次に、git protect -rm hogeで保護を解除できるようにします。

bashrc
git() {
  case $1 in
  "protect")
	if [[ $2 = "-rm" ]]; then
	  shift
	  shift
	  unprotect_branches "$@"
	else
	  shift
	  protect_branches "$@"
	fi
    ;;
  esac
}

実行してみます。

bash
~/hoge: bash

~/hoge: git protect -rm hoge fuga
hoge の保護を解除しました
fuga の保護を解除しました

~/hoge: git protect -rm hoge fuga
hoge は保護されていません
fuga は保護されていません
protected_branches.txt
- hoge
- fuga

保護と解除が出来るようになりました!

4. 保護されたブランチの一覧

git protect -aで一覧表示できるようにします。

まず、保護されたブランチを表示できるようにします。

bashrc
show_protected_branches() {
  readarray -t protected_branches < "$protected_branches_file"
  echo "保護されているブランチの一覧"
  # 連番: ブランチ名
  # !で添字を参照
  for i in "${!protected_branches[@]}"; do
    printf "%d: %s\n" $((i + 1)) "${protected_branches[$i]}"
  done
}

次に、git protect -aで一覧を表示できるようにします。

bashrc
git() {
  case $1 in
  "protect")
	if [[ $2 = "-rm" ]]; then
	  shift
	  shift
	  unprotect_branches "$@"
	elif [[ $2 = "-a" ]]; then
	  show_protected_branches
	else
	  shift
	  protect_branches "$@"
	fi
    ;;
  esac
}

実行してみます。

bash
~/hoge: bash

~/hoge: git protect -a
保護されているブランチの一覧
1: hoge
2: fuga

あとはpushを制限するだけです!

5. pushの制限

まず、指定したブランチが保護されているかを判定できるようにします。

bashrc
is_protected_branch() {
  if grep -xq "$1" "$protected_branches_file"; then
	return 0
  else
	return 1
  fi
}

次に、git push 保護されたブランチ名の場合にメッセージを表示し、pushを拒否します。

bashrc
git() {
  case $1 in
  "push")
    # "push -f"のようにオプションを付ける場合を考慮して、最後の引数だけ渡す
	if is_protected_branch "${@: -1}"; then
	  echo "このブランチは保護されています"
	  echo "pushを実行するには、保護を解除してください"
    else
      command git "$@"
	fi
	;;
  "protect")
    # 省略
	;;
  esac
}

このままだとpushとprotect以外が実行できません。
他のコマンドも実行できるようにします。

bashrc
git() {
  case $1 in
  "push")
    # 省略
	;;
  "protect")
    # 省略
	;;
  *)
	command git "$@"
	;;
  esac
}

実行してみます。

bash
~/hoge: bash

~/hoge: git push hoge
このブランチは保護されています
pushを実行するには、保護を解除してください

pushとprotect以外が実行できるかも試してみましょう。

bash
~/hoge: git status
On branch main
nothing to commit, working tree clean

完成です!
pushに怯える日々ともこれでおさらば!

おわりに

初めてbashという言語に触れたのですが、
ifやcaseの終わりがfi, esacになっていて、お洒落だな~と思いました。

参考記事

余談

今回、wsl/Ubuntu/etc/bash.bashrcを使ったのですが、

  1. Windowsのbashrc
  2. WSLのbashrc
  3. Git for Windowsのbashrc

がPC上に存在していて、最初はどれが適用されているのか分かりませんでした。
bashrcの先頭でファイルパスをechoすると迷わないのでおすすめです。

40
13
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?