この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。
こんにちは、SHIMADAです。Gitネタはたろちゃんに先を越されてしまいましたが、自分の環境でも、実際のプロジェクトでGitを実用的に使える状況になってきたので、そのへんについて書こうと思います。
■ 前提
前提条件として、
1. プロジェクトのためのsvnリポジトリがサーバーに用意されていること
2. リポジトリが
PROJECT_NAME/
`- trunk/
`- branches/
`- tags/
というSubversionの標準的なディレクトリ構成となっていること
3. ローカルに最新のgitがインストールされていること
が条件となります。
前者が揃っていないという人は、まずSubversionを導入できるように社内での推進をがんばってください。
申請書とUSBメモリがないとコミットできないんだよ……、という人は、残念ながらあきらめてください。
(あれはネタだと信じていますが……)
後者が揃っていない人は、がんばってググってインストールして下さい。
■ 下ごしらえ
さて、条件が揃ったところで、下ごしらえです。
まずローカルで、gitの設定をしましょう。
$ git config --global user.name "your name"
$ git config --global user.email account@example.com
$ git config --global color.ui auto
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.st status
$ git config --global alias.br branch
git config だと カレントワーキングツリーの .git/config に書き込まれます。
- global オプションをつけると、 ~/.gitconfig に書き込まれます。
このへんは適宜使い分けてください。
あと、 ~/.gitconfig をエディタで開いて直接編集してもいいと思います。
■ リポジトリのClone
次に、プロジェクトのリポジトリからローカルのgitリポジトリにcloneしてきます。
git svn clone -s --prefix svn/ [svnリポジトリのURL] [作成したいGitリポジトリのPATH]
svnリポジトリのURLは、/trunk をつけないプロジェクトのルートまでを書くのが注意点です。
git svn の -s オプションが、自動的に trunk と branch を見分けて git のリポジトリにとりこんでくれます。
名前がないと説明に不便なので、リポジトリの名前を仮に決めておきたいと思います。プロジェクトのリポジトリURLhttps://example.com/svn/repos/myproj/ローカルのリポジトリPATH/home/me/src/myproj-git/
この場合、上記のコマンドはこうなります。
$ git svn clone -s --prefix svn/ https://example.com/svn/repos/myproj/ ~/src/myproj-git
これで、 myproj のgitリポジトリが myproj-git/ に作成されました。
内容を見てみましょう。
$ cd ~/src/myproj-git
$ find .
$ git br -a
$ git svn info
find すると、ローカルのファイルシステムになにがあるか一覧できます。
うまくいっていれば、チェックアウトされたワークツリーと、.git/ 以下のローカルリポジトリが見えるはずです。
git br -a は、リポジトリに含まれるブランチを一覧できます。
git clone に –prefix svn/ をつけたので、リモートブランチは remotes/svn/hogehoge という風に見えているはずです。
git svn info で、カレントのローカルブランチがsvn上のどのブランチに対応しているかが分かります。
clone直後はローカルブランチはmasterのはずです。これが、svn/trunkに対応していない場合は、masterを作り直してみてください。
手順は、
- リモートのtrunkに対応したブランチを仮の名前で作成してそこに移動する
- 現在のmasterブランチを削除
- 仮の名前をmasterにリネーム
です。具体的なコマンドは、下記のようになります。
$ git co -b master2 remotes/svn/trunk
$ git br -D master
$ git br -m master2 master
$ git co master
(この項目の情報源はこちら)
全部ローカルでの作業なので、上流のsvnリポジトリには一切影響が出ません。
うまくいかなくても怖がらずに、何度でも繰り返して試せるので安心してやってみてください。
■ 作業用ブランチの作成
さて、これでプロジェクトのsvnリポジトリの完全なクローンが、手元にgitリポジトリとして作成されました。
もし、自分の割り当てられているタスクにsvnのブランチが割り当てられているなら、まずそちらに移動しましょう。
仮にブランチ名が ver02 だったとすると、手順はこうなります。
$ git co -b ver02 remotes/svn/ver02
このコマンドでやったことは、
https://example.com/svn/repos/myproj/branches/ver02 にあるブランチを元にしたローカルブランチ ver02 を作成してワーキングツリーにチェックアウト
です。
git svn dcommit は、デフォルトの動作としてローカルブランチと同じ名前のリモートブランチにコミットしに行きます。
ブランチ名 ver02 を合わせるのは、自分の分かりやすさと同時にgit-svnのためでもあります。
■ 開発環境の準備
つぎにやることは開発開発の整備です。
まず、必要なgemやライブラリをそろえた後、チェックアウトしたワークツリーで開発ができる状態になるまでコードや設定ファイルを修正することになるでしょう。
Railsならdatabase.ymlやenvironment.rbの修正などです。
いろいろ環境を設定して、script/serverが動くようになったら、ワークツリーがどうなっているか確認してみましょう。
$ git st
いろいろ表示が出てきたと思います。
既存の変更したファイルは
# Changed but not updated:
というセクションに、新しく作成したファイルは
# Untracked files:
というセクションに表示されます。
■ 開発
開発をはじめましょう。
新しいコードを書き始める前に、まずブランチをきってそちらに移ります。
$ git co -b new_feature
すると、
M ファイル名
というなにか見慣れた表示が出てくると思います。
これは、git st で
# Changed but not updated:
に表示されていたファイルです。
ワーキングツリー上では変更されているけど、リポジトリにはまだ反映されていないという状態です。
そのまま開発を続けて、一段落ついたらコミットします。
まず git st してみましょう。
# Changed but not updated:
# Untracked files:
両方のセクションに、自分がコードを書いたファイルが表示されています。
まず、Untracked files: の中にある、コミットすべきファイルをgitに教えてあげましょう。
$ git add ファイル名
次に、
$ git diff
として、自分の作業を思い返しながら変更点を見返していきます。
ここで思わぬ見落としや、作業の抜け、ミススペルなどを見つけることができます。
この「作業の振り返り」はなかなかあなどれないものがありますので、忘れずにやっておきましょう。
間違いを見つけたらすぐに diff を抜けてエディタを起動し、直してまた git diff に戻ります。
出てきたファイルごとに、これで大丈夫という状態になったら、
$ git add ファイル名
します。addされたファイルは、
# Changes to be committed:
というセクションに表示されます。また、addすると次から git diff には現れません。
git diff して確認 → OKならgit addというサイクルでひとつづつ片付けていくのがおすすめです。
あと、environment.rb など、リポジトリに変更をコミットしたくないファイルもありますね。
これは、git addをしないで
# Changed but not updated:
に置いたままの状態にします。
ここが、svnなどの普通のバージョン管理システムと違うgitの大きなメリットのひとつです。
すべての必要なファイルを git add したら、ローカルの new_feature ブランチにコミットしましょう。
$ git ci -m 'コミットメッセージ'
ここで記入するコミットメッセージは、特別なことをしない限りsvnのりビジョンログにそのまま送信されますから、
開発チームのルールに沿ったメッセージを書くようにしてください。
■ 作業ブランチからのマージと上流へのコミット
new_featureの作業が一通り終わってうまく動いているようなら、ver02ブランチに作業内容をフィードバックしましょう。
$ git co ver02
$ git merge new_feature
マージが終わったら、ver02 に new_feature で行った作業が反映されているはずです。
テストも通って、チームのコミット基準に達しているようなら、リモートのsvnリポジトリにコミットしましょう。
まず、
# Changed but not updated:
にあるファイルをワーキングツリーから片付けないといけません。
$ git stash
これで、stashと呼ばれるリポジトリ内の格納場所に、これらのファイルの変更が保存されました。
もう一度 git st してみると、ワーキングツリーがきれいになっていることが分かります。
さっきの消えてしまった変更はどこに行ったのか?
$ git stash list
これで表示される場所にあります。元に戻したい場合は、
$ git stash pop
でいつでも戻りますから安心です。
では改めて、コミット作業に戻りましょう。
$ git stash
$ git svn fetch
$ git svn rebase
まず、fetch/rebaseでリモートリポジトリの最新の状態を持ってきます。
ここでコンフリクトなどが起きていたらリポートされますので、 >>>>> ====== <<<<< のようないつものマーカーをみつけて衝突を解消してください。
衝突したファイルは、git上では unmerged な状態になっていますので、解消したら git add して、解消したことをgitに教えてやります。
衝突がすべて解決したら、あらためてコミットします。
$ git svn dcommit
これでうまくいけば、svnリポジトリに今回の作業 new_feature が反映されているはずです。
trac/redmineやほかのsvnクライアントツールなどで、無事反映されているか確認してみて下さい。
うまくいったようなら、また開発に戻るために、さきほどstashに片付けた変更を手元に戻しておきましょう。
$ git stash pop
もし、dcommit しようとしてエラーメッセージが出てしまっても大丈夫です。
作業内容はすべて git の new_feature ブランチに残っていますし、リモートのsvnリポジトリには迷惑がかかっていません。
深呼吸して落ち着いて、エラーメッセージを読んで、ググって、試して…体で git を覚えて行って下さい。
have a nice git hacking!