こんにちは、20卒エンジニアのthe96です。
弊社では、リモート下においても勉強会が日頃から開催されています。 以前、勉強会で同期のワンライナーのプロからawkを授けられて以来、ワンライナーで業務を少し改善することの楽しさに目覚めました。 この記事では、そうして生まれた、gitを使った開発が少し快適になるかもしれないワンライナーを3つ紹介します。
注意
なお、筆者は ripgrep
にどっぷりなので、たびたび ripgrep
を使うワンライナーが登場します。
ripgrep
をインストールするか、適宜 grep
に置き換えてください(動作するかは知りません)。
リポジトリ
検証などしたい場合はこちらのリポジトリをご利用ください。 https://github.com/the96/advent-calendar-2021
カレントブランチで変更したファイルのみを対象に検索する
カレントブランチ内で触ったファイルのみを対象にgrepしたいときってありませんか? そういうときにはこのワンライナーをお試しあれ。
git diff --relative --name-status --diff-filter=AM main...HEAD | awk '{print $2}' | xargs -r rg --with-filename test
このワンライナーは、カレントブランチでdiffのあったファイルのみを対象にgrepします。
コマンド中の main
の部分をお使いの環境の親ブランチに変更してご利用ください。
仕組みは結構シンプルで、前半の git diff
と awk
で差分のあったファイルの名前を抽出して、ripgrep
で検索しています。
差分のあったファイルがないブランチで実行したときのために xargs -r
を噛ませているのがミソですね。
他にも、未コミットのファイルを対象にしたい場合は main...HEAD
を --cached
に変えてあげると良いでしょう。
git checkoutで切り替えたブランチの履歴を表示する
みなさんはいろんなタスクを並行してこなしているとき、自分がどのブランチで作業していたのか思い出せなくなることはありませんか? そんな時は、このワンライナーをご活用ください。
git branch -a | sed -e 's/..//' | grep -x -f- --color=never <(git reflog | awk '$3~/checkout/{print $8}' | awk '!colname[$1]++{print $1}' | head -n 10)
このワンライナーを使うと、このようにリポジトリ内でチェックアウトしたブランチの履歴を表示することができます。
▼下のスクリーンショットでは使いやすいようにエイリアスを張っています
削除されたブランチは表示されないようになっています。
仕組み
簡単に仕組みを解説します。
git reflog
は、gitによるローカルリポジトリの操作履歴などが入っているものです。
チェックアウトの履歴はこのコマンドをもとに取り出しています。
awk
でcheckoutのログを探して、headで件数を指定しています。
そうして取り出した履歴に対して、git branch -a | sed -e 's/..//'
で現存するbranch名のみを抽出して、grepを使ってチェックアウト履歴から削除されたブランチを削除しています。
エイリアスの張り方
gitのエイリアスは ~/.gitconfig
に記述することで利用できます。
ここで設定したエイリアスは、git ***
の *** 部分を直接置換するだけなので、外部コマンドを使う場合は一工夫必要です。
まずは適当な場所にこのワンライナーをシェルスクリプトとして置いておきます。
(ここでは ~/git-checkout-log.sh
としておきます)
#!/usr/bin/env zsh git branch -a | sed -e 's/..//' | grep -x -f- --color=never <(git reflog | awk '$3~/checkout/{print $8}' | awk '!colname[$1]++{print $1}' | head -n 10)
次に、~/.gitconfig
内で下記のように !
を頭につけてエイリアスを貼ることで利用できます。
[alias] checkout-log = !~/git-checkout-log.sh
一部のブランチにコミットしないようにする
ブランチ保護ができないprivateリポジトリや、親ブランチなど、直接コミットすることを基本的に避けたいブランチってありますよね。 そういったブランチを保護する方法の一つとして、git hookがあります。
#!/usr/bin/env zsh readonly PROTECT_BRANCHES=('main' 'release' 'develop') current_branch=`git rev-parse --abbrev-ref HEAD` for protect_branch in "${PROTECT_BRANCHES[@]}" do if [ $current_branch = $protect_branch ]; then echo "WARNING: You tried commiting to protected branch($protect_branch)!"; echo " If you really wanna commit to protected branch, you can use '--no-verify' option." exit 1; fi done
このスクリプトを、対象リポジトリ内に .git/hooks/pre-commit
として配置して実行権限を付与すると、対象のブランチにコミットしようとしたときにコミットを止めてくれます。
3行目の readonly PROTECT_BRANCHES=('main' 'release' 'develop')
に任意のブランチ名をセットすれば、お好きなブランチを保護することができます。
(もはやワンライナーではないんですが、便利なので紹介したかったんです…)
時には、hotfixなどでどうしても直接コミットしたい時があると思います。
そんなときは no-verify
とつけてコミットすると git hook を無視してコミットすることができます。
終わりに
どれもちょっとしたスクリプトでしたが、みなさんの git 操作が少しでも快適になれば幸いです。