ぼっちプログラマがチームに入る前に知っておきたい6つの git コマンド

git は使っているけれど、ただログを重ねるだけ。他人とコミットのやり取りはしたことがない。そんな孤高のプログラマに、git でチームと連携するためのコマンドをそっと教えましょう。

なお、説明を簡単にするため、github のように個々人がリポジトリを持つのではなく、中央リポジトリ origin にみんなで push/pull していくものとします。

branch

まずはブランチの確認から。-a オプションで、リモートリポジトリにどんなブランチがあるか確認しましょう。

$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/maint
  remotes/origin/master
  remotes/origin/next
  remotes/origin/pu
  remotes/origin/todo

-v ではリモートと比べた位置がでます。下の例では自分の master ブランチは [ahead 1]、コミット1つ進んでいることになります。

$ git branch -av
* master                b732fd6 [ahead 1] My commit
  remotes/origin/HEAD   -> origin/master
  remotes/origin/maint  19534ee Update draft release notes to 1.8.2.1
  remotes/origin/master 8d994db Update draft release notes to 1.8.3
  remotes/origin/next   ff26027 Merge branch 'master' into next
  remotes/origin/pu     203ba97 Merge branch 'mg/texinfo-5' into pu
  remotes/origin/todo   5f3c2ea What's cooking (2013/04 #01)

もうひとつつけて -vv とすると、追跡しているブランチ名も出ます。

$ git branch -avv
* master                b732fd6 [origin/master: ahead 1] My commit
  remotes/origin/HEAD   -> origin/master
  remotes/origin/maint  19534ee Update draft release notes to 1.8.2.1
  remotes/origin/master 8d994db Update draft release notes to 1.8.3
  remotes/origin/next   ff26027 Merge branch 'master' into next
  remotes/origin/pu     203ba97 Merge branch 'mg/texinfo-5' into pu
  remotes/origin/todo   5f3c2ea What's cooking (2013/04 #01)

checkout

自分が作業すべきブランチがわかったら移動しましょう。使うのは checkout [ブランチ名] です。
今回は todo ブランチの更新を任されました。

$ git checkout todo
Branch todo set up to track remote branch todo from origin.
Switched to a new branch 'todo'
$ git status
# On branch todo
nothing to commit, working directory clean

リモートと同じブランチを作る場合 checkout ひとつで以下の3つが完了します。

  • ローカルにブランチ todo を作る
  • origin/todo を追跡ブランチ(upstream)として設定する
  • ブランチ todo へ移動する

あとはコミットを重ね、 push しましょう。追跡ブランチが設定されているので、ブランチ名を指定する必要はありません。

でもその前に、重要な設定があります。

config push.default

引数なしの git push ではすべてのブランチを push しようとします。つまり、他のブランチへの変更も問答無用で origin に送信されてしまいます。これを防ぐために push.default を設定しましょう。

  • matching すべてのブランチを push する。現時点でのデフォルト。
  • upstream カレントブランチに追跡ブランチあれば push する。
  • simple upstream と似ているが、リモートとブランチ名が同じ場合のみ push する。2.0以降ではデフォルトになる予定。
  • current カレントブランチのみ push する。リモートになければ同名のブランチを作る。

ヘルプによれば、もっとも安全で初心者へおすすめなのは simple だそうです。もちろん、プロジェクトにルールがあればそれに従ってください。

ちなみにバージョン1.8以降で初めて引数なしの push を行うと警告が出るようになりました。

$ git push
warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:
:
:

fetch

同僚が origin に送信した変更を見て欲しいと言っているけど、まだ pull できる状態ではない…。そんなときに更新情報だけを取得できるのが fetch です。

$ git fetch
remote: Counting objects: 382, done.
remote: Compressing objects: 100% (170/170), done.
remote: Total 345 (delta 161), reused 322 (delta 144)
Receiving objects: 100% (345/345), 40.43 KiB | 27 KiB/s, done.
Resolving deltas: 100% (161/161), completed with 19 local objects.
From git://github.com/vim-ruby/vim-ruby
735b918..5943faa  master     -> origin/master
From git://github.com/vim-ruby/vim-ruby
 * [new tag]         stable-20130114 -> stable-20130114

$ git log --oneline ..origin/master
(コミットログ)

..origin/master で、origin/master のコミットのうち、カレントブランチにない新しいものだけが出てきます。目当てのコミットが見つかったら、 git show [コミットハッシュ] で中身を確認しましょう。

pull –rebase

push しようとしたら origin の方が進んでいてリジェクトされた。そんなときに呪文のように「pullしてpush」と唱える人がいますが、それでは人間関係がうまくいかなくなる可能性があります。

origin にコミット a と b 、ローカルに x と y があるとします。

origin と local 両方に変更が

git pull と git push では、実は origin に既にあったコミットを自分にマージして、それから送信します。そのため、結合点でマージコミットが発生します。

git pull; git push した場合

これでは自分が持っていたコミットの方が正統としているようなものです。origin へ push したのは a と b の方が先なのに…。しかも push がかち合うたびにログがマージコミットだらけになってしまいます。

そこで便利なのが git pull --rebase です。これはマージではなく、a と b の後に自分の x と y が続くように流れを作り直します。この動作を rebase といいます。

git push --rebase の場合

origin が一本道になりました。

このオプションをデフォルトにするには2つの方法があります。

$ git config branch.develop.rebase true # 特定のブランチ (この場合は develop) のみに働く
$ git config --global branch.autosetuprebase always # 今後、branch または checkout で作ったブランチすべてに働く

rebase

新機能のために新しくブランチを作って開発をしていると、なかなか合流できずに派生元とどんどん差が広がってしまうことがあります。
あるいは、派生元のブランチから存在していたバグがあり、元のブランチでは修正されているから早く取り込みたいとき。

派生元ブランチが進んでしまった

そんなときには rebase [ブランチ名] しましょう。

$ git checkout feature-a
$ git rebase develop

rebase で分岐点を進める

派生元ブランチから分岐する地点を、最新のコミットまで移動させます。「元のブランチにあるコミットの後に自分のコミットを続ける」というのが rebase と覚えておきましょう。

まとめ

これでさみしくありませんね。でもコンフリクトが発生したら?テストに通らないコードを push する人が出てきたら?
第二弾「初めて部下を持ったチームリーダーが知りたい git 運用方法」。お楽しみに。