【Git】alias を組んだら入力補完してくれなくなったあなたへ

# お品書き
[1. はじめに](#はじめに)
[2. Gitと入力補完](#git-と入力補完)
[3. aliasと入力補完のマリアージュ](#alias-と入力補完のマリアージュ)
[4. おわりに](#おわりに)

# 動作確認環境
Git for Windows: v2.38.1.windows.1

# はじめに
個人でも仕事でも、ソフトウェアエンジニアであれば今どきソースコードの管理は Git を使っているというケースは少なくないだろう。
筆者もそのうちの一人だ。
何ならソフトウェアエンジニアでなくとも、原稿執筆や書類管理に使っているという活用例も、流れ流れて筆者の耳に (目に？) 届いたこともある。

Git とは、もともとは Linux 系の分散型バージョン管理システムのことだが、今日では Git for Windows という Windows PC 上で使用できるように手が加えられた製品も気軽にインストールして使用することができる。（デフォルト設定などに落とし穴があったりするのだが…）
とはいえ、筆者も個人や仕事でソフトウェア開発をする際は大体使っている。
個人利用の面ではお手軽バックアップを代替わりしてくれていると言ってもいい。

だが、毎回 `git` から始まるコマンドを打つのはとても煩わしい。
使用するコマンドが分かっているのであれば出来るだけ楽をしたい、というのが自分のスタンスである。
ということで、`ga` と打てば `git add` と入力したことにしてくれるような alias を .bashrc ファイルで設定し、日夜タイピング時間の削減に励んでいる。

しかし、ただ alias を設定しただけでは補完機能が効かなくなってしまう。
これでは alias 以降のコマンドを手打ちしなければならず、本末転倒もいいところだ。
Git ほど多くのユーザーに使用されている超有名なサービスならば、何か解決するための機能が用意されているはずだ。
そう信じた筆者は（個人的な）調査タスクを発行した。

今回はそんな中で見つけた、 Git コマンドの alias に対しても入力補完が効くようにする方法について共有したいと思う。

# Git と入力補完
一日に `git status` と 100 回も打ち込んではいないだろうか？
何かのご縁で Git の入力補完を知らずにこの記事に辿り着いた、そんな人のために一応説明しておくと、 Git には入力補完機能がある。
Linux 系の環境では git-completion.bash を別途インストールする必要があるのだが、 Git for Windows にはデフォルトでインストールされている。
もしかしたら Git for Windows で初めて Git を使い、その後 Linux 系 PC でも Git を使用しようとして困った人も読者の中にはいるかもしれない。

Git for Windows をインストールすると、筆者の環境では `%ProgramFiles%\\Git\\mingw64\\share\\git\\completion` 直下に git-completion.bash というファイルが人知れず作成されていた。
これは Git コマンドを使用する際の入力補完を実行するためのスクリプトファイルである。

例えば `git status` と入力したい場合は `git stat` くらいで TAB キーを入力すると `git status` と入力を保管してくれる。
`git stat` まで入力しなければいけないのは `git stash` と途中まで文字列が一緒で区別できないからだ。
`git stat` まで入力しなければいけないのであれば一緒じゃないかと思うかもしれないが、例えば `git branch` コマンドの場合はどうだろうか？
`git branch` と毎回打つのは面倒だし、入力ミスごときでエラーを吐かれるのはとても気分が悪い。
入力補完の存在を知っていれば、 `git br` まで入力してあとは TAB キーを入力するだけで `git branch` と入力を補完してくれる。
これで一件落着だ。
これで不満が解消するのであればそれで問題ない。ここでウィンドウを閉じてもらって構わないだろう。

しかし、自分は満足できなかった。
もっと楽をしたい。
唯我独尊カスタマイズを極め、自分だけに最適化された環境を作り上げたい。
そんな欲求が湧いてきたのだ。

そこで、筆者は `git status` には `gs` を、`git branch` には `gb` を、という感じに別名 (alias) を与えることにした。
これで `git stat[TAB]` と打ち込まずとも `gs` と入力しただけで `git status` と入力したのと同等の結果を得ることができるようになった。

これで一件落着かと思いきや問題が起きた。
そう。  `gb` と打ち込むと入力補完が効かなくなってしまったのだ。
これではブランチ名やオプションをすべて手打ちしなければならず、とても使い勝手が悪くなってしまう。

ただ、これは少し考えればとても論理的な結論で、 `git branch` コマンドに対する入力補完はそれまでに `git branch` と書かれているからこそ入力補完が機能するのであって、Git の入力補完機能は筆者の怠惰で身勝手な思惑までサポートしてくれるわけがない。
入力補完機能くんからしてみれば、「`gb` コマンドなんて知るか！」ということなのである。

それではどうするべきか。
筆者の怠惰で身勝手な思惑は禁欲されるべきなのだろうか。
ここで終わっていいのだろうか。

諦めの悪い筆者は懲りずに調査を続け、遂に解決の手立てが alias を設定した .bashrc ファイルに残されていることを知ったのである。

# alias と入力補完のマリアージュ
調査の手掛かりとなったのは[こちら](https://qiita.com/Sho2010@github/items/46ef3d1475dc6a6f7cba)の記事だ。
同じようなことを考えた人はいたらしい。
先人の知恵を前に感謝の念でいっぱいだった。

詳しくは上の記事を参照してほしいが、要約すると git-completion.bash を書き換えることで入力補完対象の文字列を追加していた。
「やりたいことを実現する」という意味では何ら間違いはない。
むしろ、必要最低限の労力で実現できるのであればそれに越したことはない。
ただ、筆者は少し先のことを考えてしまった。

「もし Git for Windows のアップデートで git-completion.bash の内容に修正が加わった場合はどうだろうか？」

筆者の予想としては、おそらく git-completion.bash のカスタマイズ部分もろともかき消されてしまうだろう。

しかし、手がかりは見つかった。
というのも、入力補完には `__git_complete` という関数を使ってコマンドのラッパーを内部的に作成していることが分かったからだ。
内部的な処理に関して、 git-completion.bash ファイルの該当部分には以下のようにスクリプトが組まれているようだ。

```bash
# Setup the completion for git commands
# 1: command or alias
# 2: function to call (e.g. `git`, `gitk`, `git_fetch`)
__git_complete ()
{
	local func

	if __git_have_func $2; then
		func=$2
	elif __git_have_func __$2_main; then
		func=__$2_main
	elif __git_have_func _$2; then
		func=_$2
	else
		echo "ERROR: could not find function '$2'" 1>&2
		return 1
	fi
	___git_complete $1 $func
}

___git_complete git __git_main
___git_complete gitk __gitk_main
```

バージョンの違いで多少記載内容が違う可能性はあるが、この記事の読者の環境でも概ね同じような内容が書かれているはずだ。
つまり、最後の 2 行を自分が alias として追加したい文字列に置き換えることができれば git-completion.bash を書き換えずとも同じことができるはずだ。
ということで、やってみた結果、予想は見事に的中した。
出来上がった設定は以下の通りだ。

```bash
# Aliases for Git commands
alias gs='git status'
alias gb='git branch'

if [ -f "C:/Program Files/Git/mingw64/share/git/completion/git-completion.bash" ]; then
    source "C:/Program Files/Git/mingw64/share/git/completion/git-completion.bash"

    # Adds aliases to the list of Git completions
    __git_completion gs _git_status
    __git_completion gb _git_branch

fi
```

やっていることは以下の通りだ。
1. alias を登録する。
2. git-completion.bashを探す。
3. 見つかった場合は git-completion.bash を読み込む。(見つからなかった場合はこれ以降の処理は実行しない)
4. __git_complete <alias設定した文字列> _git_<Gitコマンド> のフォーマットで入力補完してほしい文字列とGitコマンドのセットを追加する。
5. 気が済むまで 4 を繰り返す。

最後に現在の筆者の現在の設定を共有しておこうと思う。
上記以外のコマンドも alias を組みたいときの参考にはなるはずだ。

```bash
#git add
alias ga='git add'
#git branch
alias gb='git branch'
alias gba='git branch -a'
alias gbd='git branch -d'
alias gbdd='git branch -D'
alias gbm='git branch -m'
alias gbmm='git branch -M'
#git checkout
alias gch='git checkout'
alias gchb='git checkout -b'
#git commit
alias gc='git commit'
#git diff
alias gd='git diff'
#git log
alias gl='git log'
#git status
alias gs='git status'
#git submodule
alias gsub='git submodule'

if [ -f "C:/Program Files/Git/mingw64/share/git/completion/git-completion.bash" ]; then
    . "C:/Program Files/Git/mingw64/share/git/completion/git-completion.bash"

    __git_complete g __git_main
    __git_complete ga _git_add
    __git_complete gb _git_branch
    __git_complete gba _git_branch
    __git_complete gbd _git_branch
    __git_complete gbdd _git_branch
    __git_complete gbm _git_branch
    __git_complete gch _git_checkout
    __git_complete gchb _git_checkout
    __git_complete gc _git_commit
    __git_complete gd _git_diff
    __git_complete gl _git_log
    __git_complete gs _git_status
    __git_complete gsub _git_submodule

fi
```

個人的によく使うコマンドの中でリモートブランチを操作しないものに限って alias を組むという方針をとっている。
リモートブランチの操作を入力ミスで実行してしまうトラブルを避けるためだ。
トラブルが起きた場合は自己責任でしかないが、もちろんそれらを上記に含めても設定上何ら問題はない。

# おわりに
ここまで読んでくれてありがとう。
この解決方法に辿り着くまでに筆者はそれなりに時間を費やしてしまったので、今回はショートカットできる道を公開しておいた。
上と全く同じ設定をする必要はない。
むしろどういう設定にするかを考えるのもカスタマイズの醍醐味の 1 つであるから、自分の普段の癖や傾向と真摯に向き合う時間を確保してもらいたい。

また、アップデートにも対応しやすいというのがこの記事で示した解決方法の強みである。
今回は Git for Windows での動作確認しかできていないので Linux 系の PC 上での話はしなかったが、おそらく git-completion.bash のパス以外は同じように設定できるはずだ。
試してみたらぜひコメントで共有してもらえると嬉しい。

それではまたの機会にお会いしよう。
ばいちゃ！