🎺

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

2020/11/11に公開1

英語で先に書いてから翻訳しています

どうも個人アプリ作家の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みたいな、ボックスを組み合わせたモデルが簡単に作れるアプリです。それで以前イヌさんを作りました:

voxel dog

"Dev as Life"というロゴもYouTubeチャンネルで使えるようなかわいい感じで作りました。
今回のリニューアルでは、新しいホームページにこのボクセルアートを載せたいと思っています。
でも単純に画像にしたやつを載せるだけでは面白くありません。
WebGLを使って動的にモデルを描画して、ぐりぐり動かせるようにしたいと思います。
それをちょうど作業していたところで、今回の題材として最適です。

VoxelDog用のGitリポジトリを作成して登録する

現時点で、MagicaVoxelからモデルをエクスポートしてブラウザ上でレンダリングするところまで出来ました。
ここで一旦区切りをつけて、Gitリポジトリを作ってコードを入れたいと思います。

こちらがVoxel Dogのプロジェクトです。
今どんな感じかお見せします。

sc02

かわいいでしょ :)
イヌさんが机に向かってパソコンを打っています。
まだまだ改善の余地があります -- 色合いとか影の感じとか。
でもご覧の通りとりあえず動いたし、カメラも回せました。
これをGitリポジトリに入れたいと思います。
まずはリポジトリをGitHub上に用意しました:

Gitエイリアスを設定して素早くコマンドを入力する

gitを実行する時、普通は 'git' って打つと思います。
でも毎回 'git' って打つのは面倒すぎるので、 'g' と一文字にエイリアスを張っています。
以下の要領で設定できます:

  • fishシェルだと: alias g git
  • zshまたはbashだと: alias g='git'

ではローカルにGitリポジトリを初期化しましょう。

sc03

いい感じ。
次に、GitHubリポジトリをremoteoriginとして登録します。

g remote add origin git@github.com:craftzdog/voxel-dog.git

オーケー、登録されました。

Gitコマンドは毎日何回も打つコマンドです。
1日に10回打つとしたら、月に300回、年に3000回以上も打つことになります。
そしたら 'git' なんて毎回打ってられません。
'g' 一文字にエイリアスを貼るとこの負担が軽減されます。

次に、statusコマンドは 'st' にエイリアスを設定して 'g status' と打つ手間を軽減しています。
この設定は .gitconfig というファイルの alias セクションに書かれています:

sc04

このように、 'st' に status を割り当てています。
他にも沢山エイリアス設定があります。diff, checkout, commit, push, pull, branch などなど。
エイリアスは入力負担を軽減するため、2文字から4文字で設定しています。
他のエイリアスについては後ほど説明します。

今なにもステージにファイルが入っていないので、追加しましょう:

g add .

これでファイル群がステージされました。

commitizenを使っていい感じのコミットメッセージを入力する

次にそれらをコミットします。通常は g commit と打ちますよね。
するとエディタが立ち上がり、コミットメッセージの入力を行います。でもそれも何度もやるのは面倒です。
なので、僕はcommitizenというヘルパーツールを使用しています。

'g cz' とタイプすると、このように、コミットの種類をリストから選ぶよう促されます:

sc05

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

sc06

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

sc07

すると変更のコミットが作成されました。
コミットメッセージは結果的にこのようになりました:

feat(*): initial commit

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

sc08

ご覧のように、素早く各コミットを把握できます。
僕は頻繁に「何やったっけ?」と忘れてしまいます。
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プロジェクトでは、このようにどのファイルが変更されたのか素早く知ることが出来ます:

sc09

log コマンドはこのようにとても柔軟に出力形式を指定できます。
ぜひいろいろいじって遊んでお好みのフォーマット設定を見つけてください。

df エイリアスというのもあります。実行するとコミットヒストリを表示します:

sc10

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

sc11

エイリアスはこのようになっています:

[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が表示されます。

sc12

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以外のブランチで作業していた時もブランチ名の指定を省けます。
これで更にワークフローが改善します。

他にも brbranch に割り当てて短くしています:

[alias]
  br = branch

つまり、とにかくエイリアスを活用せよという話です。

ターミナルからGitHubのプロジェクトページを素早く開く方法

GitHub上にリポジトリを作りましたが、ブラウザのタブでずっと開いている訳ではありません。
もしGitHub上でissueを参照したいとか詳しく調べたいといった時、g open と入力します。

sc13

すると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を使ってイヌさんをレンダリングしています。
今、カメラがぐるぐる回っていますが、イヌさん自身も回してみましょう。

sc14

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

sc15

グレート。

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

sc16

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

sc17

これでもう1つのコミットが追加されました。
では g ps でpushします。
いい感じ。

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

sc18

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

sc19

これで、このコミットは11:53 November 5thにイヌさんを回転させるために追加されたという事が分かりました。

僕は数ヶ月前に自分のやったことを頻繁に忘れます。
でもこうすることで、いちいちgit blame コマンドを打ったりGitHub上で確認しなくても、vim上で直接過去の変更を素早く覗けます。

そして、もしそれでも分からん、もっと詳しく教えてくれとなった場合は、 :gopen コマンドを実行します。
するとGitHub上で該当するファイルをすぐさま開けます。
対応するコミットを参照してくれるので、他のコミットと差分を比較するのにも便利です。
このように、ターミナルとブラウザを行ったり来たりしています。

これをどのように実現しているかというと、vim-fugitiveというvimプラグインを使っています。
これはvimのgitラッパーです。
様々なGit関連のコマンドに対応しているので、いろいろ遊んでみてください。
gopengBrowseのエイリアスです。僕の好みです。

以上です。


お気づきかもしれませんが、チームワークと個人開発ではやはりGitの使い方が異なります。
でも今回ご紹介したものはチームワークでも活用できるTipsだと思います。
これがあなたの開発ワークフローの改善に役立つことを願っています。
ここまでお読み下さりありがとうございました。

ブログの更新通知をメールで受け取る

My YouTube channel

See also

Discussion

catnosecatnose

英語で先に書いてから翻訳しています

カッコE

それぞれ実際の活用シーンが具体的に説明されていて、とても参考になります!