git ready

learn git one commit at a time
by Nick Quaranto, O-Show(@oshow)

push と pull

committed 21 Jan 2009

今回見ていくのは、Git や類似のバージョン管理システムが持つ基本的ではあるがパワフルなコンセプト――分散についてだ。ご存知の通り、Git ではコミットは全てローカルなものであり、そして各リポジトリはお互いの単なる複製にすぎない。それはつまり、分散されたプロジェクトでは、変更を git pushgit pull を通して同期する作業が必要だという事を意味する。

Git を知らない場合、そんな作業はオーバーヘッドが大きすぎるし、コントロール不能に陥るのではないかと考えてしまうかもしれない。こう考えてみよう。もし中央サーバが落ちていたら、普通は自分の作業にも他人との協業にも支障が出る。しかし、これから作成しようとするリビジョンに関連する全ての作業が自分のマシン上に既に施されているなら、不意にネットワークが落ちていたり問題が発生していても、コーディング作業は可能だ。ほとんどの定型作業においても DVCS の方が断然速いという話はしたっけ? DVCS のその他の利点(と欠点)については Wikipedia を見て欲しい。

Oliver Steele が、push と pull が使用される様子をナイスな画像としてまとめてくれた。

図の一番上の部分は簡単だ。変更が ステージングエリア を経てコミットされる。それでひとまずバージョン管理は正しく機能するわけだが、今はそれをリモートリポジトリへ同期したい。同期先は GitHub のようなホスティングサイトや、オフィスのメイン Git サーバや、本番環境のマシンや、あるいは同僚のリポジトリかもしれない。変更が送り届けられたなら、他の人はそれを pull でひっぱって、自分の作業に使う事ができる。Git でやれる事には大体いつも何個かの選択肢があるが、今日は pushpull にこだわって見ていこう。

では現実の例について取り上げる。私はこのサイトの一番下に Twitter のリンクを追加した。そしてこの変更をプロジェクトの GitHub リポジトリpush したい。このコマンドの構文は正しくは git push <remote> <branch> だ。remote は通常、クローン元リポジトリのアドレスだ。データと履歴を同じくするリポジトリは、みな変更のアップデートを受け付けていると言えるだろう。ほとんどのプロジェクトでは remote を origin に、branch を master にすればデフォルトで動作する。

$ git commit -am "Adding twitter link"
  Created commit f2cd831: Adding twitter link
  1 files changed, 1 insertions(+), 0 deletions(-)

$ git push origin master
  Counting objects: 7, done.
  Compressing objects: 100% (4/4), done.
  Writing objects: 100% (4/4), 407 bytes, done.
  Total 4 (delta 2), reused 0 (delta 0)
  To git@github.com:qrush/gitready.git
     361303d..f2cd831  master -> master

これでリモートリポジトリがアップデートされたので、GitHub に行けば そのコミットを見ることができる。 このコマンドの出力は、変更を含んだ blob データがどれだけ転送されたかを表示する。そして SHA1 の変化により、リポジトリがアップデートされていることを教えてくれる。

では pull の方は? pull を使えば、今さっき私が push により同期したコミットを使って、他のリポジトリが自身をアップデートをすることが出来る。gitready プロジェクトの小さな小さなデプロイスクリプトは、以下だ。

$ git pull origin master
  remote: Counting objects: 7, done.        
  remote: Compressing objects: 100% (4/4), done.        
  remote: Total 4 (delta 2), reused 0 (delta 0)        
  Updating 361303d..f2cd831
  Fast forward
   _layouts/default.html |    1 +
    1 files changed, 1 insertions(+), 0 deletions(-)

この出力はサーバのリモートリポジトリから持ってこれる変更があることと、その取得の進行過程を表示している。このプロセスは、他の誰かがしたコミットを持ってきたい時も全く同じだ。GitHubで gitready リポジトリをフォークした 誰かも、私が今やった変更を受け取ることができる。このプロセスについては後のチュートリアルでもっと深く扱うつもりだ。

何か見落としているポイントや意見があれば、知らせて欲しい(ただし refspec については、後のチュートリアルで取り上げる)。