個人開発者のためのコマンドラインGit使いこなし術

個人開発者のためのコマンドラインGit使いこなし術
英語で先に書いてから翻訳しています
どうも個人アプリ作家のTAKUYAと申します。
Gitはコードベースや変更履歴の管理に必要不可欠なツールです。たとえ個人でアプリを開発していたとしても。 僕はデスクトップとモバイルの両方で動作する、InkdropというMarkdownのノートアプリを独りで開発しています。 当アプリはデスクトップ版はElectron、モバイル版はReact Nativeで作られています。 僕は開発作業は基本的にtmuxとvimでターミナル上で行っています。vimによるJavaScriptコーディングのためのセットアップについては前回シェアしたとおりです。
本稿では、僕のGitのワークフローについてご紹介したいと思います。 内容はすでにGitの基本をご存知の方向けとなります。
Gitの操作も基本的にはターミナル上で行っています。 色んなGUIベースのGitクライアントアプリを試したのですが、結局慣れませんでした。というのも、Gitコマンド自体にこれと言って大きな不満がなかったからです。 だからといって皆さんもターミナルでGitを使うべきだ!なんて言うつもりは全くありません。 すでにお気に入りのクライアントアプリをお持ちであれば、引き続きそちらを使ってください。
My Git setup
基本構成は以下のとおりです:
- コマンドエイリアス: より素早いコマンドの入力
- Commitizen: ヒューマン及びマシンフレンドリーなコミットメッセージの入力
- tig: GitのTUI
- fugitive: GitのVimインテグレーション
僕のGitの設定ファイルはGitHub上に公開しています:
以下より詳しく説明していきます。
お題: ホームページをリニューアルする
さて、Gitのワークフローをご紹介するにあたって、ちょうどよいサイドプロジェクトを見つけました。 現在のホームページは、作ってからかれこれ3〜4年経過しています。 なのでそろそろ作り直したいなと思っているところで、新しいデザインを考えていました。
ところで、MagicaVoxelはご存知でしょうか? これはボクセルアートと呼ばれるローポリでMinecraftみたいな、ボックスを組み合わせたモデルが簡単に作れるアプリです。それで以前イヌさんを作りました:

“Dev as Life”というロゴもYouTubeチャンネルで使えるようなかわいい感じで作りました。 今回のリニューアルでは、新しいホームページにこのボクセルアートを載せたいと思っています。 でも単純に画像にしたやつを載せるだけでは面白くありません。 WebGLを使って動的にモデルを描画して、ぐりぐり動かせるようにしたいと思います。 それをちょうど作業していたところで、今回の題材として最適です。
VoxelDog用のGitリポジトリを作成して登録する
現時点で、MagicaVoxelからモデルをエクスポートしてブラウザ上でレンダリングするところまで出来ました。 ここで一旦区切りをつけて、Gitリポジトリを作ってコードを入れたいと思います。
こちらがVoxel Dogのプロジェクトです。 今どんな感じかお見せします。

かわいいでしょ :) イヌさんが机に向かってパソコンを打っています。 まだまだ改善の余地があります — 色合いとか影の感じとか。 でもご覧の通りとりあえず動いたし、カメラも回せました。 これをGitリポジトリに入れたいと思います。 まずはリポジトリをGitHub上に用意しました:
Gitエイリアスを設定して素早くコマンドを入力する
git
を実行する時、普通は 'git' って打つと思います。 でも毎回 'git' って打つのは面倒すぎるので、 'g' と一文字にエイリアスを張っています。 以下の要領で設定できます:
- fishシェルだと:
alias g git
- zshまたはbashだと:
alias g='git'
ではローカルにGitリポジトリを初期化しましょう。

いい感じ。 次に、GitHubリポジトリをremote
のorigin
として登録します。
g remote add origin git@github.com:craftzdog/voxel-dog.git
オーケー、登録されました。
Gitコマンドは毎日何回も打つコマンドです。 1日に10回打つとしたら、月に300回、年に3000回以上も打つことになります。 そしたら ‘git’ なんて毎回打ってられません。 ‘g’ 一文字にエイリアスを貼るとこの負担が軽減されます。
次に、statusコマンドは ‘st’ にエイリアスを設定して ‘g status’ と打つ手間を軽減しています。 この設定は .gitconfig
というファイルの alias
セクションに書かれています:

このように、 ‘st’ に status を割り当てています。 他にも沢山エイリアス設定があります。diff
, checkout
, commit
, push
, pull
, branch
などなど。 エイリアスは入力負担を軽減するため、2文字から4文字で設定しています。 他のエイリアスについては後ほど説明します。
今なにもステージにファイルが入っていないので、追加しましょう:
g add .
これでファイル群がステージされました。
commitizen
を使っていい感じのコミットメッセージを入力する
次にそれらをコミットします。通常は g commit
と打ちますよね。 するとエディタが立ち上がり、コミットメッセージの入力を行います。でもそれも何度もやるのは面倒です。 なので、僕はcommitizenというヘルパーツールを使用しています。
‘g cz’ とタイプすると、このように、コミットの種類をリストから選ぶよう促されます:

今回は初めてのコミットなので、とりあえず ‘feat’ を選択します。 次に、変更のスコープを聞かれます:

今回は最初なので *
とします。変更範囲がすべてだからです。 次に短い説明文を入力せよと言われます。 ここでは 'Initial commit' とします。 そして次に長い説明文を入力せよと言われますが、別に詳しく説明することも無いのでスキップします。オプショナルです。 ブレーキングチェンジはありますか?いいえ。 OpenのIssueに関係しますか?いいえ。 と入力していきます。

すると変更のコミットが作成されました。 コミットメッセージは結果的にこのようになりました:
feat(*): initial commit
便利ですね。いちいちコミットメッセージのフォーマットに気を取られる必要がありません。 このように、適当になりがちなコミットメッセージを、苦労せずに美しいフォーマットで入力出来るツールです。 あなたがすべきことは事前に定義されたコミットタイプを選択することです。 深く考えなくてもいい感じのコミットメッセージにしてくれます。 チームだけでなく個人開発でも役に立つでしょう。 例えば僕の場合、アプリのリリースノートを書く時にコミットヒストリをよく参照します。 こちらがデスクトップ版のコミットヒストリです:

ご覧のように、素早く各コミットを把握できます。 僕は頻繁に「何やったっけ?」と忘れてしまいます。 3、4週間も前の作業となると全く覚えていません。 でもこのようにコミットメッセージが明快に記述されていれば、どんな変更で、どんな範囲で、そして具体的に何の変更か把握できます。 超便利。
コミットログを素早く参照する方法
ではVoxel Dogプロジェクトに戻ります。 コミットログを参照する際に打ったgit hist
もエイリアスです。
[alias] hist = log --pretty=format:\"%Cgreen%h %Creset%cd %Cblue[%cn] %Creset%s%C(yellow)%d%C(reset)\" --graph --date=relative --decorate --all
上記エイリアスはいろいろオプションを付けてフォーマットを指定しています。 他にも llog
というエイリアスも設定しています:
[alias] llog = log --graph --name-status --pretty=format:\"%C(red)%h %C(reset)(%cd) %C(green)%an %Creset%s %C(yellow)%d%Creset\" --date=relative
これはコミットログだけでなく変更されたファイル名の一覧も表示する設定です。 Inkdropプロジェクトでは、このようにどのファイルが変更されたのか素早く知ることが出来ます:

log
コマンドはこのようにとても柔軟に出力形式を指定できます。 ぜひいろいろいじって遊んでお好みのフォーマット設定を見つけてください。
df
エイリアスというのもあります。実行するとコミットヒストリを表示します:

ここでサイドバーの変更について詳しく知りたいとします。該当するコミットを選ぶと、そのdiffを表示します:

エイリアスはこのようになっています:
[alias] df = "!git hist | peco | awk '{print $2}' | xargs -I {} git diff {}^ {}"
実際には前に説明した git hist
を実行して、その結果を peco
というstdinから任意の行を選択できるコマンドラインツールに渡して、awk
で選択行からコミットハッシュを取り出して、 git diff
に渡す、という事をしています。意味不明ですね。 要するに、任意のコミットを選んでdiffを参照するワンライナーです。 これで素早くコミットの詳細を参照できる訳です。
tig — TUI for git
tigコマンドもよく利用します。 名前の通り、Gitを逆さまにしたものです。 このコマンドは、コミットをインタラクティブに選択できます。 vimライクなキーバインドに対応してるのでvimmerに優しい設計です。 例えばあるコミットを選択してエンターキーを押すと、画面が分割されてdiffが表示されます。

tig
はリリースノートを書く時に最近の変更ログを調べるのによく使っています。 なぜならコミットログを参照する度にgitコマンドを打つ必要がないからです。 これでワークフローがより効率化します。
リモートリポジトリにpushする
では、このコミットをリモートリポジトリにpushしましょう。 今1つのコミットがローカルリポジトリに入っています。 それをリモートにpushします:
g ps
出来ました。 このps
もエイリアスです:
[alias] ps = "!git push origin $(git rev-parse --abbrev-ref HEAD)"
git push origin master
なんて毎度打ってられません。長すぎですよね。 なので ps
と簡略化しています。 このエイリアスはブランチの指定も支援してくれます。 現在選択されているローカルのブランチと同名のリモートブランチにpushしてくれます。 'master'で作業しているとしたら、リモートの'master'ブランチにpushしてくれます。
pullするには、pl
を使います:
[alias] pl = "!git pull origin $(git rev-parse --abbrev-ref HEAD)"
同様に、現在のブランチと同名のリモートブランチからpullします。 こうすることで、master以外のブランチで作業していた時もブランチ名の指定を省けます。 これで更にワークフローが改善します。
他にも br
をbranch
に割り当てて短くしています:
[alias] br = branch
つまり、とにかくエイリアスを活用せよという話です。
ターミナルからGitHubのプロジェクトページを素早く開く方法
GitHub上にリポジトリを作りましたが、ブラウザのタブでずっと開いている訳ではありません。 もしGitHub上でissueを参照したいとか詳しく調べたいといった時、g open
と入力します。

するとGitHub上のリポジトリのページが素早くブラウザで開かれます。 g open
エイリアスは以下のように定義されています:
[alias] open = "!hub browse"
これは hub browse
コマンドを実際には実行しています。 つまり hub browse
を直接実行するのと等価です。 hubは、GitHub公式のコマンドラインツールで、GitHub特化のコマンドをgitに追加するものです。 例えば、GitHub上のリポジトリをcloneする時、フルのURLを指定しなくても出来ます:
g clone craftzdog/dotfiles-public
このように、GitHub特化のタスクの実行を支援してくれます。 これを使うことで、remoteとして登録されたGitHubプロジェクトページをターミナルからすぐにgit open
コマンドで開くことが出来ます。
vim-fugitiveでVimからGitを使う
僕は普段Vimでコーディングしているので、やはりVimから直接Gitを使いたい時があります。 そうするには、例えばこちらがVoxelDogのソースコードで、three.jsを使ってイヌさんをレンダリングしています。 今、カメラがぐるぐる回っていますが、イヌさん自身も回してみましょう。

オーケー、回り始めました。

グレート。
ではコミットしましょう。 ステータスを確認します。 そしてg d
を実行します。これはdiff
のエイリアスです。

オーケー、このようにイヌを回転させる行が追加されました。 このように、常にコミットする前はdiffをチェックするようにしています。 そして良さそうなら g cz
でcommitizenを実行します。 この時、 -a
オプションを指定することで、まだステージされていないファイルも一緒にコミット出来ます。

これでもう1つのコミットが追加されました。 では g ps
でpushします。 いい感じ。
ここから3ヶ月が経過したとしましょう。僕はもはやこの変更の事を覚えていません — なぜ追加したのか、いつ追加したのか、誰が担当したのかさえ。全く分かりません。 それを確認するためには、:Gblame
を以下のようにvimで実行します:

すると、コミットヒストリが左側に表示され、対応する行が右側に表示されます。 スクロールすると双方が同期します。 これで、コミットを参照しながらコードを眺められます。 もしここでエンターを押すと、diffを見ることが出来ます。

これで、このコミットは11:53 November 5thにイヌさんを回転させるために追加されたという事が分かりました。
僕は数ヶ月前に自分のやったことを頻繁に忘れます。 でもこうすることで、いちいちgit blame
コマンドを打ったりGitHub上で確認しなくても、vim上で直接過去の変更を素早く覗けます。
そして、もしそれでも分からん、もっと詳しく教えてくれとなった場合は、 :gopen
コマンドを実行します。 するとGitHub上で該当するファイルをすぐさま開けます。 対応するコミットを参照してくれるので、他のコミットと差分を比較するのにも便利です。 このように、ターミナルとブラウザを行ったり来たりしています。
これをどのように実現しているかというと、vim-fugitiveというvimプラグインを使っています。 これはvimのgitラッパーです。 様々なGit関連のコマンドに対応しているので、いろいろ遊んでみてください。 gopen
はgBrowse
のエイリアスです。これは僕の好みです。
以上です!