オイオイオイ書くわアイツ

ほうクソブログですか……たいしたものですね

`git rebase -i` と `git commit —fixup`

概要

f:id:Tak_Yaz:20171101032932p:plain

はじめに

git rebase-igit commit --fixup がハチャメチャ便利なので紹介する。 git ってなんやねんという人はすごいエリートの人が書いた記事があるので読んでみて欲しい。 この記事を書いた人はめちゃくちゃエリートで、特に何もめでたいことがなくても僕にスシを奢ってくれる人格者だ。 明日も僕にスシを奢ってくれるらしい。

前提知識: GitHub を用いた共同開発

git を利用するとファイルの管理が楽だということはエリートが書いた記事のお陰で理解してもらえたと思う。 じゃあソフトウェアを共同開発する時にも、どこかリモートのサーバ上で git を使うと便利だよねという話になる。 複数人で git を利用して開発管理をするためのプラットフォームが GitHub である。

GitHub にはプルリクエストと呼ばれる機能がある。 これは自身の加えた変更を、ある他のブランチに適用するように要求する機能である。 プルリクエストを受け取った開発者は、プルリクエストに含まれる変更を精査(レビュー)し、適切であると判断すればその変更をソースコードに適用(merge)する。

プルリクエストは機能追加のためのスースコードの変更単位としても便利なので、みんなしてプルリクエストしゅきしゅき言いながら使っている。 GitHub を用いて共同開発するときの個々人の開発フローは大体次の通りである。

  1. ローカルマシン上で変更を加えたいブランチAから新たにブランチBを切る
  2. 変更を加える
  3. 変更を git commit する
  4. 2,3 を繰り返す
  5. ローカルマシン上のブランチBをリモート(GitHub)に git push する
  6. プルリクエストを出してブランチAに自分の加えた変更を適用してくれるようにお願いする
  7. 変更に問題がなければブランチAにブランチBの変更を適用する

ここから先はGitHub上での共同開発を念頭において話を進める。 何故なら僕がGitHubを使っているからです。 また、プルリクエストとタイプするのは疲れるので今後は「プ」と表記する。 共同開発においては「プ」を上手いこと使いたいというモチベーションがあり、「プ」を上手に使うために git rebase -iやらgit commit --fixup やらが便利。

git rebase

「プ」は自分が加えた変更を人に評価して貰う最小の単位である。 「プ」を貰った人は「プ」内のコミットログやら元ブランチとの差分やらを見て、「プ」をレビューする。 「プ」を見るのが人間である以上、当然「プ」のコミットログはきれいなほうが良い。 git rebase はコミットログをきれいにするためにある。

きたないコミットログ

じゃあ一体きたないログとキレイなログとはなんなのだという話になる。 なので、今から例としてクッソきたないコミットをしていく。 下のようなマークダウンファイルが master ブランチに存在するとする。

# Funky で Groovy、ゴキゲンなリリック
俺は東京生まれ HIP HOP 育ち 悪そうなやつは大体友達
悪そうなやつと大体同じ 裏の道歩き見てきたこの街
渋谷 六本木 そう思春期も早々にこれにゾッコンに

僕は別に渋谷も六本木も好きでないので、亀有と北千住にする。 裏の道を見たこともないので、常磐線からの風景を見ていることにする。 これらの変更を no-more-party-people ブランチで行ってコミットすると、コミットログは下のようになる。

f:id:Tak_Yaz:20171101031705p:plain

で、「プ」を出そうと考える。 そこで気がつく。「あ、やべ!亀有と北千住の間のスペース全角にしてたはW」 なので、修正してコミットをする。 コミットログはこうなる。

f:id:Tak_Yaz:20171101031724p:plain

で、気がつく。「んん!W北千住の後ろに半角スペースが2つありますぞWダブルスペースはありえないWW」 修正する。コミットする。コミットログ。

f:id:Tak_Yaz:20171101031743p:plain

はい。ということでコミットログが汚くなりました。 後の2コミットは最初のコミットのミスを修正しているだけなので、本当ならば最初のコミットにまとめられていて欲しいし、ミスを修正しましたと言っているだけのコミットメッセージをログに残す必要もない。

そんなわけで、こういうコミットログの「プ」はレビュアーも疲れるし、そもそもこういうコミットログをmergeしてしまうと、全体のコミットログを汚染し過去の変更を辿るのを困難にする。 そういうことを考えて、レビュアーは「プ」に対して下のようなコメントを残し、mergeを保留するだろう。

f:id:Tak_Yaz:20171101032932p:plain

きれいなコミットログとgit rebase -i

こういうきたないコミットログを作り出してしまった時にgit rebase -iをする。 git rebase が何かと言った説明は省く。 このページが結構わかりやすい。 ブランチを統合する前準備として、コミットログをひと連なりにしてきれいにしてくれる。

git rebase-i というオプションをつけると、ブランチを統合するための前準備を対話的に行える。 今回はmasterブランチに統合したいのでgit rebase master -iというコマンドを実行する。 これがすごい便利。 コマンドを実行すると以下のような画面が開く。 vimだ……

f:id:Tak_Yaz:20171101033140p:plain

画面には各行にコミットログが並べられている。 画面下部にも書いてある通り、各行の左端に pick と書いてあるコマンド部分を reword やら fixup やらの他のコマンドに書き換えてあげると、好き勝手にコミットを操作できるのである。 しかも、行を並べ替えることでコミットの順序の変更もできる。

今回のきたないコミットログでは、最後の2コミットは「最初のコミットに統合されていてほしいもので、コミットメッセージも無くなってよいもの」である。 画面下部の説明によると、左端の pickfixup にすれば良さそうである。

f:id:Tak_Yaz:20171101033201p:plain

:wq として変更を保存し終了すると、なんとコミットが修正され、コミットログがきれいになっている。すごい。

f:id:Tak_Yaz:20171101033220p:plain

git commit --fixup

上の例は完全におふざけだったが、実際の開発でもあるコミットのタイプミスを修正したいとか、変数名を変えたいという状況は多々発生する。 当然、そういう変更は可能な限り1つのコミットにまとめてコミットログをきれいにしたいので、git rebase -i を多用することになる。 ここで、あるコミットが他のどのコミットに対する修正なのかを把握しておくのが手間になってくる。 こういう時に便利なのが git commit --fixup である。

git commit --fixupgit commit --fixup ${commitへの参照} の形で使う。 git commit --fixup で作られたコミットは、最初からあるコミットを fixup するためのものとして扱われる。 あるコミットへの参照は、 ':/${コミットメッセージ}' を使うとやりやすい。

例えば、全角スペースを半角スペースに修正したコミットは当然 Fix, party people town -> sumiyasui town のコミットを fixup するためのものである。 なので、 git commit --fixup ':/Fix, party people town -> sumiyasui town' というコマンドを実行する。 すると、fixup! Fix, party people town -> sumiyasui town というメッセージでコミットが作成される。 連続半角スペースを削除するコミットは、本来ならば全角スペースを半角スペースに修正した時に一緒にやっていたかったものなので、同じように git commit --fixup ':/fixup! Fix, party people town -> sumiyasui town' というコマンドを実行する。 結果として、コミットログは次のようになっている。

f:id:Tak_Yaz:20171101033236p:plain

この状態で git rebase master -i を実行する。 すると、初期状態で既に fixup コマンドがセットされている! あとは:wqで保存するだけ。楽!便利!

f:id:Tak_Yaz:20171101033248p:plain

おわりに

「プ」は後々実装を振り返るためにも重要な情報を提供してくれる。 去年僕は電子情報工学科のTAをやっていたが、「プ」やIssueをちゃんと使って開発を進めていたチームのコードは、どの部分が何のために書かれたのかがわかりやすく、凄く評価しやすかった。 高い点をつけようという気持ちになった。あくまでも気持ちの話。

「プ」とIssueをちゃんと使うだけでなくコミットログのきれいさも意識するようにできれば、後からコミットログを振り返るだけでプロジェクト全体の概観が把握できるようなサイコーのリポジトリが作れると思うので、人々にはぜひ git rebase -igit commit --fixup を使って欲しい。