Git 業務で役に立ったコマンド達
業務でGitを使うようになって完全に理解した*1ので、役に立ったコマンド達をここに記しておく。
Git編
その前に
Gitコマンドは割と雰囲気で使っていたが、特に$ git checkout --help
と$ git reset --help
を見たら思ってたのと違う概念だったので先におさらいしておく。
checkout
$ git checkout branch
で特定のブランチに移動する、あるいは特定のブランチの状態をワーキングツリーに再現する。
前者の概念はみんな知っているけど、後者の概念は最初触った時にはあまり意識できていなかった。
特定のブランチの状態をワーキングツリーに再現するので、現在のブランチで何らかの変更をしてしまっても$ git checkout branchname
あるいは$ git checkout .
でそのブランチの最新の状態(つまり、変更を行う前)に戻すことができる。
reset
$ git reset
は、何かをリセットするもの...ではない。
$ git reset
の定義は、「現在のHEADの指している位置を変更する」。*2
一番よく使うのは$ git reset --hard HEAD^
だろうか。意味は「HEADが指す位置をHEAD^、つまり一つ前のコミットに変更する」となる。
HEAD, HEAD^
HEAD
: 現在チェックアウトしているブランチの一番最新のコミットHEAD^
: 現在チェックアウトしているブランチの一番最新のコミットから、一つ前のコミット
ここから、役に立ったコマンド達
PRを作るまでもないけど、作業ブランチとmasterとの差分を知りたい
実装前の設計のために、素振りでコードを変更している時によく使う。
$ git diff branch_name master
最後のコミットとの差分を知りたい
出社して朝一発目はこれを打つことが多い。
$ git diff HEAD^
特定のファイルだけ、特定のコミットの状態にしたい
$ git checkout commit_hash filepath
例えば、Gemfileだけmasterの状態にしたかったら$git checkout mastser Gemfile
とか。
マージをなかった事にする
$ git reset --hard ORIG_HEAD
master
ブランチにいると思い込んで、作業ブランチで$ git merge master
をしてしまった時にお世話になった。
作業ブランチにmasterの変更を取り込むこと自体はそんなに致命的ではないが、あるPRからさらにブランチを派生させて作業していたため、$ git diff topic_branch1
とのdiffが汚染されてしまったために使った。
$ git checkout topic_branch1 && git merge master && git push
とかでも良いかも。
ちなみにORIG_HEAD
は以下のような概念。
実は git merge のような「危険」な(= 現在のブランチの内容を大幅に変える可能性のある)コマンドの場合、 実行前の状態を ORIG_HEAD という名前で参照できるようになっています。 つまり、わざわざコミットログを確認しなくても以下のコマンドで マージ前の状態に巻き戻すことができます:
あるブランチでの変更の一部を、別のブランチに取り込む
デザイナーさんの実装待ちの時に、先にロジックだけ自分のブランチで実装してた時に使った。 みんな大好きcherry-pickの出番です。
$ git cherry-pick commit_id
やる事自体は普通のマージコマンドと同じ。 当然コンフリクトも有り得る。
内容としては、そのコミットで修正されているファイルがあったら、そのファイルの状態をマージしようとする。
コンフリクトしたら解決するかcherry-pickを中止するかを選べる。
解決するなら、そのファイルを修正して$ git add .
した後$ git cherry-pick --continue
でマージを実行。
中止するなら、$ git cherry-pick --abort
でcherry-pick
を発行する前の状態に戻せる。
マージする時のコミットメッセージはデフォルトでcherry-pickでマージしたコミットのコミットメッセージを引っ張ってくる。
cherry-picked from hogehoge-commit
とかそういう気の利いたコミットメッセージにはならないので注意。
マージした後コメントだけを直す場合は普通に$ git commit --amend
で直せばいい。
リモートにpushしてしまったけど、コミットを直したい
ローカルで変更を加えて$ git commit --amend && git push -f
。-f
をつけないとpushが弾かれる。特に複数人で触っているリポジトリのmasterブランチにはやってはいけない。*3
masterではないブランチから、さらにブランチを切って作業する時に、masterの変更を取り込みたい
派生元にしたいブランチ、例えばhoge-buranchがあったとして、それをチェックアウトしてから$ git checkout -b fuga-branch
と発行して、ブランチからブランチを派生させた時の話。
よくあるのが、大元のまとめブランチをPRのベースとして作っておいて、そこから各機能をさらにブランチを切って作業をするパターン。
少しややこしいので以下に状態をまとめる
master <- hoge-branch <- fuga-branch
fuga-buranch上で$ git merge master
をしたが、hoge-branchは手をつけていない場合、PRのdiffにマージした内容が表示されてしまう。
この場合は、一度hoge-branchでmasterをマージしてから、fuga-branchからhoge-branchをマージする必要がある。
コマンド的にはこう。
$ git checkout master $ git pull origin master $ git checkout hoge-branch $ git merge master $ git checkout fuga-branch $ git merge hoge-branch
masterに作業ブランチをマージしてしまった
これはfuga-branch
をhoge-branch
にマージしようとして、間違えてmasterブランチ上で$ git merge fuga-branch
と打ってしまった時。
マージも一つのコミットなので、reset
で戻すことができる。
$ git reset --hard HEAD^
--hard
はインデックス(ステージ)とワーキングツリーをリセットする。
おまけ:tig編
git
コマンドでできることを、CLI上でグラフィカルに表示してくれるツール。
地味にvimとキーバインドが違う(Gとかdとか)ので割と脳がバグるが、git
で微妙に手が届かないところを強力にサポートしてくれる。
簡単な使い方
MacOSなら、$ brew install tig
でインストールできる。$ tig
で起動。コミット一覧が簡単に見られる。
操作は以下のような感じで。*4
- メインビュー(↑のコミット一覧画面)でEnterを押すとコミットの詳細が画面分割で表示される。
jk
で上下移動、<C-u>
,<C-d>
でページ移動。普通のd
は画面分割なしでコミット詳細が表示できる。- diff中に
<C-n>
,<C-p>
でコミットの親、子を移動できる。いちいちコミットを選びなおす必要がないので楽。 t
を押すと、変更されたファイルがツリーで表示される。- メインビューで
s
を押すと現在のワーキングツリーのgit status
表示。変更ファイル一覧が出るので、Enter
でdiffを見れる。 - どのビューでも、
m
でメインビューに戻ることができる。 - メインビューでで
h
を押すと、ブランチ一覧表示、ブランチ選択中にCでそのブランチをチェックアウトすることができる。 q
で前の画面に戻る。$ tig --all
でリモート含めた全ブランチが見える。$ tig [filename, dirname]
でファイルorディレクトリが関わる履歴のみが見える$ tig [branchname1, branchname2]
で対象ブランチに関わる履歴のみが見える
tigでBlameがしたい
t
で変更ファイルの一覧ツリーを表示してる画面で、ファイルを選択した状態でb
を押すと、現在選択している行のファイルに対してのBlameが見られる。
この機能の素晴らしい点として、,
を押すと、Blameを再帰的に遡ることができる。
例えば、あるメソッドをblameで見ると、定義自体はだいぶ古いけど、中身の処理は頻繁に変更されている場合に「どういう経緯があって、今この状態にあるんだろう?」という歴史を見たいケースがある。
そういう時にtigでBlameビューを表示し、,
を押すと、そのファイルに対して再帰的にBlameを実行することができ、最新の変更をする前にはどのような処理がなされていたのかを知ることができる。
本家のgit
コマンドで実現しようとしたら、$ git log filename
でそのファイルのコミット一覧を見て、1個ずつblameしていく感じになると思う。*5
tigでGrepがしたい
$ git grep
の代わりに、$tig grep some_method_name
でgrepできる。grep画面でEnter
を押すとそのファイルに、b
を押すとそのファイルに対してBlameができる。
メインビューでg
を押してもgrepができる。
おわりに
色々調べたけど書ききれないぐらい色んなことができる。$ git config --help
や$ man tig
で調べてGitライフを捗らせていきたい。