アリスとボブのサーバー、git pushをちゃんと理解したい!



アリスとボブのGitシリーズが本になりました!
  アリスとボブのGit入門レッスン

上記の日記から続く、アリスとボブの記録。

前提条件

  • アリスとボブは同じマシンにログインする異なるユーザー。
  • ファイルシステムからアクセスする分には、サーバーの設定は不要になるので、これで話がシンプルになる。

共通gitリポジトリの準備

最近、アリスにはちょっとした悩みがあった。

  • 現在、このプロジェクトはアリスとボブの二人で、修正したら連絡を取り合って、お互いの変更をダウンロードする(git pullする)ことで同期をとっていた。
  • しかし、プロジェクトメンバーが増えた場合、このやり方では同期する手間が煩雑になってしまう...。
  • 理想は、サーバーとなるgitリポジトリを決めて、作業前にそこからダウンロード、修正したらそこにアップロードを繰り返す方式にしたい。

アリスがボブに相談すると、ボブはアリスのマシンで操作して、あっという間に実現してくれた。

alice/project$ git clone --bare /Users/alice/project /Users/Shared/project.git
Initialized empty Git repository in /Users/Shared/project.git/
  • 上記コマンドで作成されたフォルダのアクセス権を、everyone読み/書きOKにして、内包している項目すべてに適用した。(Finderから操作した。)
  • git cloneはgit管理のフォルダをコピーするコマンドなのだが、--bareオプション*1を指定することで...
    • /Users/alice/project/.gitフォルダを/Users/Shared/project.gitフォルダへコピーしてくれる。(gitが管理するスナップショットと設定だけがコピーされる。完全に同じではなく、サーバーとして必要な設定になるようだ)
    • gitにとって重要なのは、変化の履歴をスナップショットとして保存したデータとその設定、つまり.gitフォルダであり、
    • ユーザーが操作するテキストファイルは、作業結果を記録する一時的なファイルでしかない。(...と思う。)


これで、/Users/Shared/project.gitという共通のgitリポジトリが出来た。

  • アリスとボブは今後、作業の前後に/Users/Shared/project.gitと同期することによって、お互いの作業を確認し合うことになる。*2
  • 具体的には以下の操作。(今はコピーした直後なので、同期された状態だ。)
alice/project$ git pull /Users/Shared/project.git master
From /Users/Shared/project
 * branch            master     -> FETCH_HEAD
Already up-to-date.
alice/project$ git push /Users/Shared/project.git master
Everything up-to-date
  • git pushによって、/Users/Shared/project.gitのmasterブランチへアップロードしている。

ボブの作業

  • ボブは前回修正したaboutメソッドにバグを見つけた。早速、新しい運用方法でgitを操作してみる。
  • まず最初にボブは、/Users/Shared/project.gitにsharedという略称を設定した。(この方が簡潔に入力できる)
  • ボブはその後、共通リポジトリsharedのmasterブランチからプル。
bob/myrepo$ git remote add shared /Users/Shared/project.git
bob/myrepo$ git pull shared master
From /Users/Shared/project
 * branch            master     -> FETCH_HEAD
Already up-to-date.
  • 式展開を含む文字列をシングルクォートで囲っていたので、ダブルクォートに変更した。
# About git
Class WhatIsGit
  def show
    puts 'Git is easy, if you understand the basis.'
  end
  
  def about(lang = 'en')
    puts "http://#{lang}.wikipedia.org/wiki/Git"
  end
end
  • ボブはその後、コミット
bob/myrepo$ git commit -a -m "changed to double quotation marks"
Created commit f85e8dc: about URL changed3
 1 files changed, 1 insertions(+), 1 deletions(-)
  • ボブはその後、プッシュ
bob/myrepo$ git push shared master
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 291 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/Shared/project.git
   52cfe0d..16150ca  master -> master

無事、共通gitリポジトリに反映されたようだ。

アリスの作業

  • ところで、アリスが作業する前にプルすると...
alice/project$ git pull /Users/Shared/project.git master
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /Users/Shared/project
 * branch            master     -> FETCH_HEAD
Updating 52cfe0d..16150ca
Fast forward
 what_is_git.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
  • 何らかの変更がダウンロードされたようだ。アリスは履歴を確認してみた。
alice/project$ git log
commit 16150ca79dc873b972edb6570bf750a99ddf80fe
Author: bob 
Date:   Wed Sep 10 16:36:59 2008 +0900

    changed to double quotation marks

commit 52cfe0de979425dbf1dcef3d081e06ea40a68965
Merge: 616c5cb... fb7c82f...
Author: alice 
Date:   Mon Sep 8 17:44:48 2008 +0900

    Merge /Users/bob/myrepo
    
    Conflicts:
        what_is_git.rb

commit fb7c82fda542762554792fc9b198428a3e6ae5b3
Author: bob 
Date:   Mon Sep 8 16:11:45 2008 +0900

    git is easy!

...(中略)...
  • アリスはさらに詳細を確認すると...
$ git show
 commit 16150ca79dc873b972edb6570bf750a99ddf80fe
 Author: bob 
 Date:   Wed Sep 10 16:36:59 2008 +0900

     changed to double quotation marks

 diff --git a/what_is_git.rb b/what_is_git.rb
 index 103a58e..ac3f723 100644
 --- a/what_is_git.rb
 +++ b/what_is_git.rb
 @@ -5,6 +5,6 @@ Class WhatIsGit
    end
   
    def about(lang = 'en')
 -    puts 'http://#{lang}.wikipedia.org/wiki/Git'
 +    puts "http://#{lang}.wikipedia.org/wiki/Git"
    end
  end

アリスは「ボブもたまには間違うのね!」と呟いた。

所感

  • 当初、git pushはgit pullとはデータの流れが反対の動きをするだけで、あとは同じと考えていた。
  • しかし、実際に使ってみると、それ以外に大きな違いがあることに気付く。
    • git pullは履歴データを受け取る人が、自分の好きなタイミングで実行することが出来る。
    • git pushでは、データを受け取る人は、外部からいつのタイミングで送信されてくるのか予想できない。
  • そのため、git pullは自分の作業ディレクトリ*3でそのまま実行し、同期された内容に作業ファイルの状態も即更新されるが、
  • git pushは、git push専用の.gitフォルダを用意して、その専用フォルダに対してのみgit pushする仕様となっているようだ。
    • もし、ファイルを修正中に外部から次々プッシュされ最終のコミットが変化てしまったら、そのユーザーは混乱してしまうことになるだろう。
    • /Users/alice/projectフォルダに対してgit psuhすることも可能なようだが、運用としてgit pushしないようにするのが一般的なようだ。
    • フォルダにアクセス権を設定しておけば、勘違いのgit pushも防止できるはず。

*1:bare=裸の、むき出しの、という意味らしい

*2:もちろん、今までのgit pullでも同期できるが、/Users/Shared/project.gitが最新の状態になっていないと、せっかくボブが設定した意味がない。

*3:.gitフォルダ以外の、実際に編集するファイルを含むフォルダ