GitLabにgitリポジトリを登録し開発できるようにしてみる

こちらの記事(2011-11-02 - ike-daiの日記)を参考にGitLabの導入ができたかと思います。
その後、新規でProject登録して、Userも登録して開発できるようにしたいと思います。

新規PJの登録方法

GitLabにログイン後、「New Project」からプロジェクトを作成します。
Name,Path,Codeに作成するPJの情報を入力します。
Pathの情報のみ、登録後は変更できません。
作成したProjectではここのPathで指定した名前のgitリポジトリを使っていくことになります。

これで新規Projectが作成されました。
このままではまだ何もgitリポジトリは作成されていません。

鍵の設定

環境構築時に作成した秘密鍵を用いて手元の環境から「git@hostname:sample.git」という形式でGitLabのサーバにアクセスするための設定を実施。
Linuxマシンからであれば下記のように設定します。
~/.ssh/configに下記内容を追記

Host hostname
  HostName 192.168.xx.xx
  IdentityFile ~/.ssh/id_rsa

上記設定は/etc/ssh/ssh_configに設定でもOKです。

gitリポジトリの作成

登録後に下記のような画面が表示されます。

この内容に従ってgitリポジトリを作成していきます。
gitリポジトリは開発環境など手元の環境で作成します。

開発環境など手元の環境で下記を実行

$ mkdir sample
$ cd sample
$ git init
$ touch README
$ git add README
$ git commit -m 'first commit'
$ git remote add origin git@hostname:sample.git
$ git push -u origin master

これでGitLabサーバ上にリポジトリが登録されます。

あとは、自分の環境内で変更をcommitし、pushすればGitLabでその変更が反映されていきます。

ユーザの追加

開発ユーザを追加したい場合は、
管理者がGitLabにユーザ登録を実施し、アカウントを発行します。

そのユーザを割り当てたいProjectに登録します。
Projectに登録しないとどのリポジトリにもアクセスすることはできません。

ここまでは管理者が実施します。
その後、アカウント情報をユーザに伝え、以降はユーザ側で作業を実施します。

キーペアの作成

構築時と同様にユーザのキーペアを作成します。
右上の「自分のアカウント名」→「Keys」の順に進み、「Add new」を実施します。
titleに適当な名前を登録し、keyの欄に先ほど作成した公開鍵を貼り付けます。

これだけでこの鍵を用いてgit clone、pushが可能になります。

遭遇した困ったこと

post-updateがうまく動かないため、authorized_keysに追記されない問題の対応

新規で鍵を登録しても/home/git/.ssh/authorized_keysが更新されないということがありました。
鍵登録、削除時にはpost-updateというhookスクリプトが実行されています。
その中身は下記のようになっています。

#!/bin/sh
set -e
gitosis-run-hook post-update
git update-server-info

post-updateのスクリプト内にエラー出力をするように書き込んで、実際の画面から鍵登録。
すると下記のようなエラーが発生

Traceback (most recent call last):
  File "/usr/bin/gitosis-run-hook", line 9, in 
    load_entry_point('gitosis==0.2', 'console_scripts', 'gitosis-run-hook')()
  File "/usr/lib/pymodules/python2.7/gitosis/app.py", line 24, in run
    return app.main()
  File "/usr/lib/pymodules/python2.7/gitosis/app.py", line 38, in main
    self.handle_args(parser, cfg, options, args)
  File "/usr/lib/pymodules/python2.7/gitosis/run_hook.py", line 75, in handle_args
    post_update(cfg, git_dir)
  File "/usr/lib/pymodules/python2.7/gitosis/run_hook.py", line 43, in post_update
    config=cfg,
  File "/usr/lib/pymodules/python2.7/gitosis/gitdaemon.py", line 79, in set_export_ok
    assert ext == '.git'
AssertionError

/usr/lib/pymodules/python2.7/gitosis/gitdaemon.pyこのファイルの中で、/home/git/repositoriesの中にあるディレクトリをチェックし、
リポジトリ名の一覧を取得してきます。
そのディレクトリ名の中で、「.git」で終わっていないものがあると、assert ext == '.git'の条件に当てはまらずAssertionErrorが発生するようです。
なので、/home/git/repositoriesの中には必ずxxx.gitという形式の名前でgitリポジトリだけを登録して下さい。
そうしないとエラーが発生します。

cloneに失敗する場合の対応
$ git clone git@hostname:sample.git

という形でcloneした場合に下記のようなエラーが発生する場合は、鍵を確認して下さい。

$ git clone git@hostname:sample.git
Initialized empty Git repository in /home/git/repositories/sample.git
fatal: 'sample.git' does not appear to be a git repository
fatal: The remote end hung up unexpectedly

http://d.hatena.ne.jp/thimura/20101008/gitosis#20101008f4
ここに書かれているように、通常のログインに使われる鍵と同様にしていた場合、gitlab経由でログインできないようなので、
id_rsaのようなデフォルトの名前ではなく、gitlab用の鍵の名前にしてssh_configを設定するといいかと思います。


また、git cloneしようとした際に鍵認証ではなく、パスワード認証が聞かれた場合は、ssh_configが読み込まれているかどうか確認して下さい。
.ssh/configの権限についても見なおして下さい。
ownerユーザからの書き込みだけを許可するようにchmod 644にして下さい。

masterブランチがないリポジトリを利用した場合に500エラー

既存のリポジトリを管理下に置きたい場合に発生するかもしれないエラーです。
commitログを見ようとすると500エラーが発生しました。

Started GET "/deltacloud/commits/e1c6809ff390bafaf128101598d46a85b8384bc0b" for  
  Processing by CommitsController#show as HTML
  Parameters: {"project_id"=>"deltacloud", "id"=>"e1c6809ff390ba52aafafa598d46a85b8384bc0b"}
Rendered commits/_diff_head.html.haml (79.3ms)
Rendered commits/_text_file.html.haml (0.8ms)
Rendered commits/_text_file.html.haml (0.2ms)
Rendered commits/_text_file.html.haml (0.2ms)
Rendered commits/_text_file.html.haml (0.2ms)
Rendered commits/_text_file.html.haml (0.2ms)
Rendered commits/_text_file.html.haml (0.2ms)
Rendered commits/_diff.html.haml (108.9ms)
Rendered notes/_notes_list.html.haml (0.6ms)
Rendered notes/_form.html.haml (3.1ms)
Rendered notes/_notes.html.haml (4.1ms)
Rendered commits/show.html.haml within layouts/application (115.0ms)
Rendered layouts/_flash.html.haml (0.1ms)
Rendered layouts/_head_panel.html.erb (5.2ms)
Rendered projects/_top_menu.html.haml (9.6ms)
Completed 500 Internal Server Error in 144ms

ActionView::Template::Error (undefined method `id' for nil:NilClass):
    28:   - if @commit
    29:     %span= link_to truncate(commit_name(@project,@commit), :length => 15), project_commit_path(@project, :id => @commit.id), :class => current_page?(:controller => "commits", :action => "show", :project_id => @project, :id => @commit.id) ? "current" : nil
  app/helpers/application_helper.rb:8:in `commit_name'
  app/views/projects/_top_menu.html.haml:31:in `_app_views_projects__top_menu_html_haml__7153559fafa859057_24443740'
  app/views/layouts/application.html.haml:23:in `_app_views_layouts_application_html_haml___15805912fafa2185993_43892440'
  app/controllers/commits_controller.rb:33:in `show'

cache: [GET /favicon.ico] miss

↑これはapplication_helper.rbのcommit_nameに送られてくるcommitの中にidが含まれていないことによるエラーです。
application_helper.rbの該当箇所をコメントアウトするとコミットログの内容を確認することができた。
暫定的に対応しました。

また、treeを見ようとしてもエラーになりました。

Started GET "/deltacloud/tree"
  Processing by ProjectsController#tree as HTML
  Parameters: {"id"=>"deltacloud"}
Rendered public/404.html (0.4ms)
Completed 404 Not Found in 22ms (Views: 2.1ms | ActiveRecord: 1.2ms)
cache: [GET /favicon.ico] miss

ソースコードの中身を見てみると
projectcontroller.rbのtreeメソッドにおいて、

  def tree
    load_refs # load @branch, @tag & @ref

    @repo = project.repo

    if params[:commit_id]
      @commit = @repo.commits(params[:commit_id]).first
    else 
      @commit = @repo.commits(@ref || "master").first
    end

branchやtagの指定が無く、tree表示を試みようとした場合に、デフォルトでmasterを指定してコミット情報を取得するような設定になっていました。
ブランチに「master」がなく、trunkしかない場合にエラーが@commitがnilになり、エラーが発生するようです。
暫定的に下記のように変更

  def tree
    load_refs # load @branch, @tag & @ref

    @repo = project.repo

    if params[:commit_id]
      @commit = @repo.commits(params[:commit_id]).first
    else 
      if @commit = @repo.commits(@ref || "master").first
      else
        @commit = @repo.commits("trunk").first
      end
    end