2013年12月23日月曜日

git commit -am"{add,fix,del}" が大好きな後輩達に覚えてほしいgitの便利コマンド

はぐれメタルです.タイトル通りです.日頃私がよく使っている(もしくはまれに使うけど)便利なgitのコマンドを紹介していきたいと思います. これを見てcommit -amを卒業しよう!

git fetch

リモートリポジトリの変更を取り込むのに,

git pull
# or
git pull origin master

等としていませんか?

実はgit-pullサブコマンドは,2つのサブコマンドを実行しています.1つ目はgit-fetch,2つ目はgit-mergeです.

git-fetchは,リモートリポジトリに適用された変更を,ローカルリポジトリに取得するためのサブコマンドです.

git fetch

と引数なしで実行することにより,リモートリポジトリ<origin>から,すべてのブランチの最新状態を取得できます.リモートリポジトリにおけるmasterブランチは,ローカルリポジトリではremotes/origin/master等として表されます.ローカルリポジトリでこれらのブランチをcheckoutすることで,Webインターフェース等を用いることなくリモートブランチの状態を参照できます.

git fetch
# Omitted output
git branch -a
* master
  remotes/origin/master
git checkout origin/master

fetchした内容は,git-pullを実行するまでローカルリポジトリのブランチには反映されないので,安心して実行できます.リモートリポジトリの状態を把握しておくために,定期的にgit-fetchを実行する癖をつけましょう.他のgitコマンドと一緒に使いこなすことで,Webインターフェースに頼らなくても作業ができるようになります.

git add -p

git addは,gitの管理下にないファイルや,変更が加えられたファイルをステージする(次のコミット対象にする)コマンドです.

gitのコミットはなるべく小さい単位で作るのが良いとされています(私の経験からもこれは事実だと思います)が,現実的には,コミットの単位を意識してファイルを編集するより,一通り頭の中にある実装を書き出してからコミットを作ることのほうが多いでしょう(そのほうが効率も良いでしょう).

そういう時に,現在存在する編集を,意味的にまとまりのある単位に分割してコミットする必要があります.ファイル毎に分かれていれば,ファイル毎にgit addしてコミットを作れますが,1つのファイルに複数の意味単位が存在したり,変更が広範に渡る場合は,git-add -pを使うのが良いでしょう.

-pは,ファイルのステージングをインタラクティブに行うことを指定するオプションです.git-add -pを実行すると,gitの管理下にある,変更が加えられたファイルのdiffがセグメント毎に次々表示されます.次回のコミットに含めたいセグメントの場合は,y(yes),含めない場合はn(no)を指定することで,1つのファイルにまとまったコミットを分解することができるし,変更された箇所をすべて一度表示してくれるため,ステージング漏れも起きにくくなります.その他にも色々操作があるので,詳しくはman git-addINTERACTIVE MODEセクションを読みましょう.

git cherry-pick

git-cherry-pickは,他のブランチで発生したコミットを,そのブランチをマージすることなく取り込みたい時に使用します.

例えば,masterブランチから派生したhogeブランチで作業中に,masterブランチで発生したコードのバグを修正したとします.(strictなgitの運用では,bugfixブランチ等で修正コミットを行ってから取り込むのが正しい方法でしょうが,現実的には面倒なので現在のブランチにコミットしてしまったりしますよね・・・?) しかし,masterブランチでも開発は進行するため,hogeブランチで行ったバグ修正のコミットは直ぐにmasterブランチに適用したい,でもhogeブランチ全体をmasterにマージするわけにはいかない,という時に,cherry-pickが使えます.

git checkout master
git cherry-pick <COMMIT HASH>

とすることで,masterに<COMMIT HASH>で指定されたコミットだけを取り込むことができます.

git blame

git-blameは,ファイル毎に各行を変更したもっとも新しいコミットと,そのコミッターを表示してくれるコミットです. blameという単語には,非難する,とがめるという意味があるので,このコマンドはあるバグを仕込んだ(当該行の)コミットを作った人物を探し出す,といった目的を意識して作られたように思います.

git-blameはバグを仕込んだ犯人探しにも有用ですが,ポジティブな使い方もできます. 多人数で開発をしていると,他人の書いたコードを読んだ時に,そのコードが何を意図して書かれたのか分からなかったり,もっと簡潔に書ける方法があるのに!と思うようなことがあります.そういったときに,git-blameを使ってそのコードを書いた人を知ることができれば,その人物に聞いたり,教えたりすることができます.

git stash

git-stashは,コミットもステージング(git addされた状態)もされていない変更を一時的に退避するためのサブコマンドです.

次のようなメッセージを見たことがあるかと思います.

git checkout hoge
error: Your local changes to the following files would be overwritten by checkout:
    hoge
Please, commit your changes or stash them before you can switch branches.
Aborting

これは,checkoutしようとしている先のブランチにおいて,現在のブランチで変更された1つ以上のファイルと同じファイルが変更されているため,現在の変更内容を失わないよう,gitがcheckoutを差し止めた状態です.

このような時に,

git add hoge
git commit -m"tmp"

等として乗り切るのは間違っていて,stashを使うことで正しく乗り切ることができます.

git stash save      # hogeの変更内容を一時退避する
git checkout hoge
git checkout master # masterに戻ってきた
git stash pop       # stashに退避していた内容を復元する

git-stashの主な使い方は^^に示したようなものですが,stashは複数作ることもでき,復元も任意のstashを任意の順に復元できるため,使いこなせると捗ります.詳しくは:

man git-stash

git stash -p

git-stash -pは,git-add -pのstash版です.git stash saveとした場合は,すべての変更がstashに入ってしまいますが,-pオプションを指定することで,一部だけをインタラクティブにstashすることができます.

他にも紹介したいコマンドやテクニックはまだまだありますが,とりあえずはこのあたりを使いこなすことが中級者への第一歩ではないかと思います.

また,gitコマンドを一通り使いこなせるようになった後は,tigを使ってみたり,EmacsユーザであればMagitを導入してみることで,作業効率がとても上がるかもしれません.

0 件のコメント:

コメントを投稿