あなたの知らないGit Tips
注意:いくつかのコマンドやオプションは Git の version
1.7.2 以降が必要です。
OS Xでは、
Homebrew で簡単にアップグレードできます:
brew install git
git log でブランチとタグも見る
$ git log --oneline --decorate
7466000 (HEAD, mislav/master, mislav) fix test that fails if current dir is not "hub"
494a414 fix cherry-pick of a commit URL
4277848 (origin/master, origin/HEAD, master) whoops
d270fae bugfix: git init -g
9307af3 test deps
8ccc17e http://github.com/defunkt/hub/contributors
64bb19c bugfix: variable name
546726a dont need you
3a8d7af (tag: v1.3.1) v1.3.1
197f429 (tag: v1.3.0) v1.3.0
a1e1a50 not important
3c6af16 magic `cherry-pick` supports GitHub commit URLs and "user@sha" notation
diff で行の全てではなく、変更された単語部分のみハイライトする
$ git diff --word-diff
# Returns a Boolean.
def command?(name)
`type -t [-#{command}`-]{+#{name}`+}
$?.success?
end
このオプションは git log -p や git show などの、diff のためのオプションを使えるところなら動作する。
短い status 出力
$ git status -sb
## thibaudgg...thibaudgg/master [ahead 1, behind 2]
M ext/fsevent/fsevent_watch.c
?? Makefile
?? SCEvents/
?? bin/fsevent_watch
git status のデフォルトの冗長な出力は初心者にはいいのだが、一旦 Git に慣れてしまえば必要でなくなる。私は status のチェックをよくやるので、出力はできるだけ簡潔であって欲しい。
ブランチの push と同時に追跡のセッティングも自動的に行う
$ git push -u origin master
# "master" ブランチを "origin" リモートへプッシュして、さらに追跡させる
”追跡”とはつまり、ローカルブランチとリモートブランチの間のリンクのことだ。他のブランチを追跡しているローカルブランチ上で作業しているなら、git pull と git push に何も引数を渡さなくても、Git は何をするかわかってくれる。
しかしながら git push はデフォルトでは、同じブランチ名がリモート上にあるならそれらを全て push してしまう("matching" 戦略)。この振る舞いを現在のブランチのみの push に限定するためには、以下の設定を行う。
$ git config --global push.default tracking
これで、まだ push する準備が整っていないブランチを誤って push することが避けられる。
(2012年03月07日追記) Git 1.7.4.2からは push.default のための "tracking" という値は、"upstream" という名前になりました。意味は同じです。また "tracking" という名前は今後も使えるようです。
(2014年09月19日追記) Git 2.0からは push.default のデフォルトが "simple" という値になりました。"simple" では、カレントブランチと同名のリモートブランチがある場合のみ、カレントブランチをそこへ push します。Git のヘルプでは、これが最も安全で初心者にも向いた設定であると説明されています。
他人のリモートブランチを簡単に追跡する
$ git checkout -t origin/feature
# "feature" ブランチを作成してチェックアウトし、
# "origin/feature" を追跡させる。
チームメイトが作業していたブランチをその人と共有することになり、あなたもそれに対して変更を行うつもりなら、それに対応するローカルブランチを作らないといけない。上記のコマンドではブランチの作成とともに追跡のセットアップもやってくれるので、あなたは変更を作成した後にただ git push するだけでよい。
ブランチをチェックアウトし、master へ rebase して merge する
# "master" ブランチ上にいるとき:
$ git checkout feature && git rebase @{-1} && git checkout @{-2} && git merge @{-1}
# "feature" を "master" へ rebase して、それを master へ merge する
"@{-n}" という特別な構文は「現在から数えてn個前にチェックアウトされていたブランチ」という意味だ。"feature" がチェックアウトされたなら、"@{-1}" は "master" を表している。rebase した後、"@{-1}" は rebase の内部処理により "feature" を指すことになるので、今度は "@{-2}" を使って master をチェックアウトする。
更新: Björn Steinbrinkh がこれはコマンド2つでも可能だと指摘してくれた:
$ git rebase HEAD feature && git rebase HEAD @{-2}
(
訳注:自分の手元では、このコマンド2つの場合がうまく動かなかった(Gitのバージョンは1.7.3.2)のですが、もし試してくださる方がいたら、結果をブログコメントか
Twitterなどで教えてくだされば嬉しいです)
pull のとき merge ではなく rebase する
$ git pull --rebase
# 例) "master" ブランチ上にいるなら、 `git fetch origin` をしてから、
# `git rebase origin/master` を実行したのに等しい。
Git ではブランチのマージはマージコミットを記録するので、それらは深い意味を持つ――例えば、ある機能がリリースブランチにマージされたのがいつなのかを示すなど。しかしながら、ある1つのブランチを何人かのチームメンバと頻繁にやりとりするような日常的なワークフローでは、普通に git pull していると不必要な細かいマージコミットでタイムラインが汚染されてしまう。rebase ならコミットを常に再適用してくれるので、コミット履歴は直線的な一本のままでいられる。
--rebase フラグをつけなくても特定のブランチでは常に rebase するようにしてくれる設定がある:
# master 上で `git pull` するときは常に rebase を使う
$ git config branch.master.rebase true
上の設定を、全ての新しい追跡ブランチでもやるようにする設定もある(グローバルに設定している):
# 全追跡ブランチで rebase を使う
$ git config --global branch.autosetuprebase always
(2012年03月7日追記)Git 1.7.9 からは pull.rebase という config 項目が増え、これを true に設定すると git pull に何もつけなくても rebase になります。これを設定しても、例えば branch.master.rebase が false なら、master での git pull は merge が選択されます。優先されるのは個々のブランチの設定というわけです。
# 全追跡ブランチで rebase を使う・その2
$ git config --global pull.rebase true
ある変更がどのリリースの一部なのか見つける
$ git name-rev --name-only 50f3754
"tags/v2.3.8~6"
コミットの SHA-1 ハッシュはわかるのだが、そのコミットがプロジェクト履歴のどこに位置しているかわからないということは珍しくない。もしあなたが私に似ているなら、多分あなたはその変更があるリリースで発生したのか、それとも違うのかが知りたいだろう。そのコミットに対して
git show を使えばコミットメッセージは見れるし、日付も差分も見られるのだが、それらはちっとも助けてはくれない――特に、コミットした日付と、それを成果物に適用した日付が必ずしも一致しないような時には。
name-rev コマンドはプロジェクトにおいてコミットと関係のあるタグを教えてくれる。上記の例は Ruby on Rails リポジトリから持ってきたものだ。この場合は "v2.3.8" とタグ付けされる6つ前にそのコミットが位置していることを教えてくれている――つまりこの変更は Rails 2.3.8 に存在していると確定できる。
このコマンドはさらに有用性がある。いくつかのコミットに言及するような議論に参加したとしよう:
このバグは e6cadd422b72ba9818cc2f3b22243a6aa754c9f8 で混入したものだが、私の記憶が確かなら 50f3754525c61e3ea84a407eb571617f2f39d6fe で修正されている。
上の文章をクリップボードにコピーして
git name-rev へパイプで渡すと、文章中にあるコミットの SHA-1 ハッシュを認識してそれぞれにタグ情報を付加してくれる:
$ pbpaste | git name-rev --stdin
"このバグは e6cadd422b72ba9818cc2f3b22243a6aa754c9f8 (tags/v2.3.6~215) で混入したものだが、
私の記憶が確かなら 50f3754525c61e3ea84a407eb571617f2f39d6fe (tags/v2.3.8~6) で修正されている。"
併せて読みたい: git help describe
ある変更が含まれているブランチを見つける
$ git branch --contains 50f3754
このオプションはブランチのリストを、指定したコミットがそのブランチの祖先に存在するものだけを表示するようにフィルタリングする。"-a" フラグをつければ、リストにリモートの追跡ブランチも含めてくれる。
あるブランチの上流に既に存在している変更を知る
# "feature" ブランチにいる場合に:
$ git cherry -v master
+ 497034f2 Listener.new now accepts a hash of options
- 2d0333ff cache the absolute images path for growl messages
+ e4406858 rename Listener#run to #start
cherry コマンドは例えば、開発中のブランチから安定しているブランチへ cherry-pick が行われたコミットを調べるのに便利だ。このコマンドは現在(feature)のブランチと上流(master)のブランチを比較して、両方に存在しているものには "-" をつけて表示する。上流にまだ存在しない変更には "+" マークをつける。
正規表現にマッチするコミットメッセージを持つ最後のコミットを表示
$ git show :/fix
# メッセージ中に "fix" を含む最後のコミットを表示
$ git show :/^Merge
# 最後のマージコミットを表示
複数のリモートからまとめて fetch する
$ git config remotes.default 'origin mislav staging'
$ git remote update
# リモートの "origin"、"mislav"、"staging" をfetch
remote updateするコマンドで fetch される対象になる、デフォルトのリストを決めることができる。あなたのチームメイトや、オープンソースプロジェクトでの信頼できるコミュニティメンバ、等からのリモートだ。また、関連するグループに名前をつけて定義することもできる:
$ git config remotes.mygroup 'remote1 remote2 ...'
$ git fetch mygroup
コミットの注釈を書く
$ git notes add
# 最後のコミットに注釈を追加するためにエディタが開く
Git の notes は既に存在するコミットへの注釈だ。それらはリポジトリの歴史を変更しないので、どんなコミットにも自由に追加することができる。notes はあなたのリポジトリにしか保存されないが、他のリポジトリと
共有することも可能だ。notes には
興味深いユースケースのアイデアだってある。
"hub" をインストール
Hub は Github について Git に教えてくれる。もし日常的に Github のリポジトリを利用しているなら、あなたは間違いなく hub をインストールしてキーストロークを減らしたくなる――特にあなたがオープンソースに関わっているのなら。