その1でsubmoduleをaddし、git-submodule statusコマンドでステータスを確認するところまでの作業をしました。
今度はaddした以外の人がpullして、submoduleを確認するところを書いてみます。

submoduleを取得:init & update

   1  git pull --rebase #submoduleを追加したコミットを取得
   2  git submodule 
   3  -e110f2056783465b8d719bdb1ab5fd14e7650f56 vendor/plugins/rspec

(-がついているので)この時点ではrspec submoduleが初期化されていません。よって下記のコマンドで初期化します:

   1  git submodule init
   2  git submodule update

又は

   1  git submodule update --init

updateすることによりソースファイルを取得します。
これで、addした以外の人もsubmoduleを追加することができました。しかし、まだこれで終わりではなくて実はいくつか検討すべき点があります:

  • submoduleに修正を加えないかどうか
  • どのバージョンを使うか:commit hash
  • (railsの)deployはどうするか:Capistrano
  • submoduleの削除

外部のrepoをそのままか、forkしてからか

submoduleをaddする前に検討すべき事項です(!):
追加するremoteリポジトリを変更したくなる可能性があるかどうか検討する必要があります。例えばrailsやrspecなら変更を加えるというのはほとんどないように思われますが、完成度の低いpluginだと自分で修正したり、追加したりすることが考えられます。そのような場合、下記のようなシナリオが考えられます:

  1. remoteをsubmodule(変更しない)
  2. Githubであればforkして、それをsubmoduleにする
  3. 自分のローカルにcloneして、それをsubmoduleにする
  4. サーバにrepoを作ってremoteのファイルを追加、それをsubmoduleにする

1,2はなんとなく想像できますが、3,4は運用が面倒そうです...
また、railsまでsubmoduleにする記事もあったのですが、毎回deploy時にコピーすることになるのでdeployに時間がかかるだろうし、容量も食うので運用には向いていないかもしれません。

どのコミットをsubmoduleとして採用するか

submoduleを利用する際、外部のbleeding edgeブランチを積極的に採用したくはありません。なので、タグか特定のバージョン(コミット)を利用するのが適切です:

   1   cd vendor/plugins/rspec/rspec
   2   git tag 
   3  1.1.10
   4  (略)
   5  1.2.1
   6  1.2.2
   7   git checkout 1.2.2
   8   cd ../../..

rspecのタグ1.2.2を採用しました。このあとRAILS_ROOTに戻ってcommit, pushすればokです。
この後、他の人がこの変更を反映するには下記の作業を行います:

   1  git pull --rebase #submoduleを追加したコミットを取得
   2  git submodule update

Capistranoでsubmoduleを使えるようにする

一行追加するだけ!

   1  set :git_enable_submodules, 1

via http://github.com/guides/deploying-with-capistrano

submoduleの削除

rspecを例に:

  1. .gitmodulesファイルから該当する行を削除
       1  [submodule "vendor/plugins/rspec"]        
       2  path = vendor/plugins/rspec        
       3  url = git://github.com/dchelimsky/rspec.git
    
  2. .git/configファイルから該当する行を削除

       1  [submodule "vendor/plugins/rspec"]        
       2  url = git://github.com/dchelimsky/rspec.git
    

  3. git rm --cached path_to_submodule
    パスの最後に/(スラッシュ)がない状態で:

       1  git rm --cached vendor/plugins/rspec
    

  4. git commit、pushでおしまい

via http://git.or.cz/gitwiki/GitSubmoduleTutorial

.gitmodulesファイル

初めてsubmoduleを追加すると、下記のファイルが追加されます:

   1  .gitmodules

その他に.git/configも変更されます。

submoduleをもっとよく理解するRefs

posted by Png satoko on Tue 7 Apr 2009 at 21:24

[追記] その2を書きました:
http://blog.s21g.com/articles/1411


長くなりそうなので続きはその2で!

railsを使っているとpluginなどは外部repoをそのまま使いたくなります。そこで前から聞いていたsubmoduleを使ってみたくなりました。しかしこのsubmodule、わりと最近導入されたようなのでgitのバージョンによって動作に違いがあるようです。

というわけで、まず私の環境を書いておきます:

   1  % git --version
   2  git version 1.6.0.2

git submodule add

rspecを例に:

   1  % git submodule add  git://github.com/dchelimsky/rspec.git vendor/plugins/rspec

追加したらcommit and push

   1  % git commit -am "add submodule: plugins/rspec" 
   2  % git push origin master

これでサーバにsubmoduleが追加されました。他の人がpullなどすれば、submoduleを確認することができます(詳しくはその2を参照)
で、次にsubmoduleのstatusを確認してみます。

git submodule status

git statusと同じようなコマンドでsubmoduleの状態が確認できます:

   1  % git submodule status 
   2  9dc19a3a593f4ce1b4e221889091cebd773ea5c4 vendor/plugins/cache_fu (heads/master)
   3  -e110f2056783465b8d719bdb1ab5fd14e7650f56 vendor/plugins/rspec 651611999df3e57de6f36486b51abd3bf5d66cea vendor/rails (v2.2.0-1085-g6516119)

commit hashに-、+がついている時がある(上だとrspecに-がついてます)。
ざっくり説明:

  • -がついているとまだ初期化されていない状態
    => git submodule update --initでok
  • +がついているとサーバでindexしているcommit hasと異なるcommit hashだよというお知らせ
    => git submodule updateでok
posted by Png satoko on Fri 3 Apr 2009 at 17:26

iPhone appのバージョンアップを申請後、時期verを開発継続している際にrejectされた、という場面があったので、タグ・ブランチでの運用を始めました:ezPhotoMail2度目のrejectを食らってしまいました orz

rails@githubの場合:命名

ブランチ:バージョン+stable/unstableの形
http://github.com/rails/rails/tree/2-3-stable

タグ:タグ名はvが入っている形
http://github.com/rails/rails/tree/v2.3.2.1

railsを参考にezPhotoMailでの運用を決めました、下記。

ezPhotoMailでの運用:命名

appリリース後、新しいバージョンをリリースする場合はタグを付けます:タグは後付けも可能。 ブランチ名にはタグ名のvがない、数字だけのものを採用することにしました。

ex

  • タグ名:v1.1
  • ブランチ名:1.1

タグ名とブランチ名を同じにするとcheckoutやshowなどでrefspec(refs/heads/1.1, refs/tags/v1.1などの形式)を挙げねばならず運用が面倒。

ezPhotoMailでの運用:rejectされた

  • タグ名のvを取ったブランチがあるか確認、なければブランチを作成して修正
       1  git branch -r
       2  git checkout -b 1.1 refs/tags/v1.1 #1.1ブランチを作成してcheckout
       3  git push origin HEAD:refs/heads/v1.1 #HEADはカレントブランチ。refs/heads/v1.1はサーバ上のブランチ名
    
  • ブランチがあれば、checkoutして修正
  • Info.plistのversionの末端を+1する:1.1→1.1.1
  • 申請用のzip作成:appName_1.1.1.zip
  • add, commit・push
  • (各ブランチを最新にして)1.1ブランチをmasterブランチにマージ
       1  git checkout 1.1
       2  git pull --rebase origin v1.1:1.1 #v1.1=サーバブランチ
       3  git checkout master
       4  git pull --rebase origin master #サーバでもローカルでも同じ名前master
       5  git merge 1.1 #masterに1.1をマージ
    
  • 申請作業

ezPhotoMailでの運用:申請が通った

ブランチのInfo.plist内のバージョンを確認して、タグを作成。

posted by Png satoko on Wed 25 Mar 2009 at 12:01

おまけにしようと思ったのですが、長くなりそうなので別記事にします。

ブランチv1.1をサーバにpushする:

   1  % git push origin refs/heads/v1.1

タグv1.1をサーバにpushする:

   1  % git push origin refs/tags/v1.1 
   2  Counting objects: 1, done.
   3  Writing objects: 100% (1/1), 159 bytes, done.
   4  Total 1 (delta 0), reused 0 (delta 0)
   5  To ssh://git.s21g.com/mnt/git/ezPhotoMail.git
   6   * [new tag]         v1.1 -> v1.1

ローカルのタグをすべてサーバにpushする:

via http://github.com/guides/push-tags-to-github

   1  % git push --tags

サーバのタグを取得するには

tagをpushしたサーバ上のrepoをcloneすればtagも勝手に取得してくれるようです。cloneしてから、tagのブランチを作れば内容が確認できます。

   1  % git tag -l
   2  v1.1
   3  % git checkout -b 1.1 refs/tags/v1.1

又はブランチを作らずに内容を確認:

   1  % git checkout refs/tags/v1.1

posted by Png satoko on Fri 13 Mar 2009 at 16:19

ブランチ、タグ両方にv1.1があると、ambiguousだと怒られました。

   1  % git show v1.1
   2  warning: refname 'v1.1' is ambiguous.

ということで探してみたら、下記の記述:

fmfm フルパス?で指定してみると、うまく表示されました!:

   1  % git show refs/tags/v1.1  

posted by Png satoko on Fri 13 Mar 2009 at 12:35 with 2 comments

各コミットに割り当てられるSHA1は長いので、その頭数桁をabbreviated commit hash/commit checksumなどと呼びます。適当な長さで良いようです:ex. 7-8桁。

数桁って何桁やねん!と思って探したのですが、見つけられませんでした。そういえば昔何かのlibraryの作者にバグ報告したときに、githubのコミットSHA1の頭五桁を送ってくれって言われたことがありました。ということで適当でいいみたいですね。この適当さ加減が良い。そしてそういう風にも使えるのですね。

このhashはtag設定時等に指定できます:

   1  % git tag -a v1.1 0d86f96 -m "version 1.1"
   2  % git show fb47ddb2

Pretty formatsのformatに記述されていました: abbreviated commit hash

%h: abbreviated commit hash
http://www.kernel.org/pub/software/scm/git/docs/git-show.html#_pretty_formats

learn.githubでタグ時の説明に:commit checksum

And I forgot to tag the project at ‘v1.2’, which was at the ‘updated rakefile’ commit, I can add it after the fact. To tag that commit, you can just specify the commit checksum (or part of it) at the end of the command.

$ git tag -a v1.2 9fceb02
http://learn.github.com/p/tagging.html#tagging_later

posted by Png satoko on Fri 13 Mar 2009 at 12:25 with 2 comments

サーバ管理をしていて、root権限が必要なディレクトリに、ファイルをリポジトリからgit cloneしてきたい状況になったので、方法をメモしておきます。 まず状況の確認として、

  • gitのプロトコルにはsshを使っている
  • リポジトリサーバには、rootユーザでは鍵認証でもパスワード認証でもログインできない
  • リポジトリサーバ、clone先のサーバ双方ともfooというローカルユーザが存在。sshでリモートログインできる

という感じです。ユーザ権限でアクセス出来る場所にgit cloneする場合であれば、

   1  foo% git clone ssh://git.repos.com/path/to/repo.git

こんな感じで済むのですが、ファイルの作成にroot権限が必要な場合、 repoディレクトリを作成出来なくて怒られます。 かといって、rootユーザでgit cloneしようとしても、リポジトリサーバにはrootではログイン出来ないのでcloneできません。

そのような場合には、以下の手順を踏みます。

  1. clone先のサーバに ssh -A foo@target.server.com でエージェントフォワードしてログイン。
  2. ssh -A root@localhost でエージェントフォワードした状態でlocalhostにrootユーザでログイン(ターゲットサーバ上での、ローカルからのrootによるssh接続は許可する必要がある)
  3. git clone ssh://foo@git.repos.com/path/to/repo.git でclone

これでroot権限が必要な場所にfooユーザのSSHエージェントを介してリポジトリサーバに接続し、cloneできます。

注意

安全にエージェントフォワーディングを行う事が出来るのは、 接続先および踏み台にするのサーバ群の管理者たちが全て信頼できる場合に限られます。

posted by Png genki on Tue 10 Mar 2009 at 02:34

弊社は、deployツールとしてcapistranoを使っています。 しかし、Capistranoのメンテナンスが終了するという話("Jamis Buck氏, CapistranoやSQLite/rubyの開発を終了"参照)を聞いても、 特に困らないという事に気がついて、あらためて驚きを感じました。

なぜだろうと考えてみると、それはGitとGitHubの存在による所が大きい。 GitHubにソースがある限り、メンテナが不在でも勝手にforkして 野良patchを書いたり、それを集めてきてちょっとした stable release的なものを作ったりする事ができてしまう。

もちろんそれは、今までだって頑張れば出来た事だけれど、 Git/GitHubは、それを全く違う次元で簡単にしてしまった。

かつてはメンテナやコミッタが専権的にソフトウェア開発の決定権を握っていた構造が、Git/GitHubの登場によって、気がつかないうちに崩れ去っている。 これはソフトウェア開発史上、非常に大きな出来事なんだろう。

See Also

posted by Png genki on Thu 5 Mar 2009 at 03:58

Xcodeで開発しているiPhoneアプリをgitで管理する場合には、 以下のような .gitignore ファイルを使っています。

   1  *.xcodeproj/*.mode1v3
   2  *.xcodeproj/*.pbxuser
   3  build
   4  .DS_Store

posted by Png genki on Wed 4 Mar 2009 at 18:36

ハマったので覚えるために記事にしました。

サーバ等で

   1  $ mkdir repo.git
   2  $ cd repo.git
   3  $ sudo git init --bare --shared=true

"空"の共有リポジトリができました。

ローカルマシンで

その後、remote add, add, commit, push

   1  git init
   2  git remote add origin ssh://git.s21g.com/mnt/git/repo.git 
   3  git add .
   4  git commit -m "initial import"
   5  git push origin master

サーバのrepo.gitにファイルが追加された時点でcloneできるようになります。空のリポジトリをcloneしようとしてもエラーが出ます:

   1  $ git clone ssh://git.s21g.com/mnt/git/repo.git 
   2  fatal: no matching remote head

おまけ:git URLを確認する git remote show origin

   1  git remote show origin
   2  * remote origin
   3    URL: ssh://git.s21g.com/mnt/git/repo.git

posted by Png satoko on Thu 19 Feb 2009 at 14:21