Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2722

Git Hooksでgit cloneだけをフックする

$
0
0

やりたいこと

git clone実行後だけリポジトリディレクトリに対して特定の処理がしたい。

TLDR

  • trap DEBUGgit cloneを叩いたことを検知して、コマンド実行前にフラグを立てる。
  • post-checkoutスクリプト内でフラグをチェックして分岐させる。
  • 今回の記事の本筋ではないが、注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要あり。

背景

前の記事で、gitアカウントを自動で切り替えるためにgit clone前に処理をする必要があったので、cdgitのラッパー関数を作り、エイリアスで元のcdgitを上書きして、cdをフックにgitコマンドが使用する変数を切り替えるようにしました。しかし、他のライブラリを利用してcd以外でディレクトリ移動するケースを考えるとやはり汎用性に欠け、取り急ぎとはいえ筋が良くなかったので、潔くgit cloneを直接フックすることにしました。

意外にもgit cloneだけをフックする方法に関する記事を見かけなかったので書きました。記事がないということは全く必要とされていないのか、それとも記事にならないほどもっと楽な方法があるのか、知ってる人が書いてないだけなのか。

ちなみに、GitHooksとは、というお話は以下を参照。
git hook はじめの一歩
git hookでできること

問題

Git Hooksでgit cloneをフックしたいとき、post-checkoutを使う必要がありますが、これだとgit checkoutのときにも実行されます。

解決策

環境

macOS

sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.5
BuildVersion:   18F132

Git

git --version
git version 2.23.0

Bash

bash --version
GNU bash, version 5.0.11(1)-release(x86_64-apple-darwin18.6.0)

git cloneの実行を検知する

Gist: .bash_hooksとして置いておきました。使い方はGist冒頭に書いてあります。このGistには、ディレクトリ移動の検知や、コマンド実行前だけでなくコマンド実行後に実行される処理もまとめて書いているのですが、今回の記事に関わるポイントは以下の3点です。

  • 各コマンドの実行前に__hooks__before_each_commandが実行されるようにする
trap'__hooks__before_each_command' DEBUG
  • __hooks__before_each_command内でBASH_COMMANDで直前のコマンド名(=叩かれたコマンド名)を取得
  • フックがアクティベートされていたら(この上記Gistの最後でアクティベートしてます)__hooks__set_git_clone_flagに直前のコマンド名を渡して実行
function __hooks__before_each_command(){local last_command=($BASH_COMMAND)if[-z"$__HOOKS__ACTIVATED"];then
        return
    fi# before each command
    __hooks__set_git_clone_flag "${last_command[@]}";if["$PREVPWD"!="$PWD"];then# on changing directoriesexport PREVPWD="$PWD"fi

    if[-z"$__HOOKS__EXECUTING_LINE"];then
        return
    fi

    unset __HOOKS__EXECUTING_LINE
    # before each first command of a comamnd line}
  • 直前に叩かれたコマンド名がgit cloneだった場合、__hooks__set_git_clone_flag内で__HOOKS__ON_GIT_CLONEフラグを立てる
function __hooks__set_git_clone_flag(){if['git'="$1"]&&['clone'="$2"];then
        echo"Setting __HOOKS__ON_GIT_CLONE=true in $filename"export __HOOKS__ON_GIT_CLONE=true
    fi}

post-checkout内でフラグをチェックして処理する

Gist: post-checkoutとして置いておきました。.gitvariablesというファイルを置いてgitアカウントの情報をロードするようにして、そのファイル自体は~/.gitignoreに登録してトラックしないようにしてあります。

  • ここでフラグをチェックして、フラグが立ってなかったらexitしてます。
if[-z"$__HOOKS__ON_GIT_CLONE"];then
    exit
fi
  • 処理の最後にフラグを倒します。
unset __HOOKS__ON_GIT_CLONE

GitHooks中でユーザの入力を待ちたいときの注意点

オフトピックですが注意点として、GitHooksは標準入力を利用しないので、処理の中で入力を待ちたい場合はターミナルからリダイレクションする必要があります。ちょっとハマりました。

read-rp'Type anything you like:'< /dev/tty

まとめ

コードが散在することと、暗示的にフックすることでハマったりしないように、多用には注意が必要ではありますが、cdとgit上書きより汎用的かつ拡張しやすくなった感はあります。

ちなみに、Bashのコマンドの実行前後をフックする方法の解説はChuan Ji: DEBUG trap and PROMPT_COMMAND in Bashの記事がわかりやすいです。

参考


Viewing all articles
Browse latest Browse all 2722

Trending Articles