2012年10月14日日曜日

Git入門



これまで仕事ではソースコードの形態管理にSubversionを使ってきました。しかし最近、世の中が分散形態管理システムのGitが評判になってきており、ちょっと試してみようと思いました。しかし、調べてみても一般的なコマンドの説明ばかりで、具体的にGitサーバーをどう設定したらいいのかとかまとめてあるのが見つかりません。この土日でやってみたのをまとめておきます。具体的には以下のような環境です。



自宅で用意したものです。クライアントはもっと種類増やしてもいいんですが、まとめるのが大変なのと、Gitが基本CUIでGUI環境があまりよくない、あと日本語文字コードの扱いに問題があるとのことだったので、UTF-8に統一してあります。


X.Gitのインストール

Ubuntu等のマシンで以下を実行してgitのパッケージをインストールする。
$ yum install git-core (Ubuntuは sudo apt-get install git-core でした)

WindowsではGitoliteがクライアントとしてよさげ。
と思ったら、Eclipseだと標準でGitプラグイン(EGit)が入っており、「インポート」で普通にサーバーを選択できた。
(Gitコマンドはファイル名→右クリックの「チーム」のサブメニューにある)

MacだとXcodeでgitクライアントのCUI版はインストールされるらしいが、GUI付はGitXがいいらしい。
(でもこれは0.7で開発が止まってるように見える。日本語大丈夫だろうか?)
(入ってなかった。ググったらcode.googleにあるよ!)


0. サーバーの設定
基本Ubuntuはクライアント利用が前提であり、最近は特にセキュリティの問題からサーバー関係のプログラム(サービス)は特に自分からインストール・設定してやらないといけません。(Redhatでもかなりまえにtelnetdが外されて(パッケージすらなくなった!)びっくりした)

最初にgit用にアカウントを作ります。リポジトリは基本この下におきます。(管理者権限を付加しておいたほうが後々便利です。設定後はとったほうがいいですが、このあとgitアカウントで設定いろいろしますから)

まずsshをインストールしないといけません。
「ソフトウェアセンター」で入れましょう。(sudo apt-get install sshdだと ないと言われた。名称が少し違うようだ)

ところでデフォルトではsshからrootでログインできてしまいます!(ダメやん、そんなの)
$ sudo vi /etc/ssh/sshd_config

PermitRootLogin no ← noにしておく

$ sudo /etc/init.d/ssh restart

でsshサービスを再起動しましょう。
念のため以下のコマンドでちゃんと起動しているか確認。

$ sudo lsof -nPi:22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 3750 root 3r IPv4 16769 0t0 TCP *:22 (LISTEN)
sshd 3750 root 4u IPv6 16771 0t0 TCP *:22 (LISTEN)

さて実際に使うにはssh鍵をサーバー、クライアントの双方に登録してやらないといけません。一番簡単なのはクライアント→サーバにsshでログイン(このとき鍵の生成を聞かれて、登録されます)。再度、サーバーからクライアントにsshでログインしなおす(これで双方のssh鍵が互いに登録されます)
ただ今回はサーバ:Ubuntu、クライアント:Macで試してますが、Mac側が当然のごとくsshだろうがリモート接続は許してくれません。
クライアント(Mac)でssh鍵を生成します。

$ ssh-keygen -t rsa

ここでパスワードを聞かれますが、複数のマシンでパスワードが異なってるとめんどくさいので、いんちきですが「空」でリターンだけ押してやります。2回聞かれますが、それでポスワードが「空」の鍵が生成できます。(せめてすべてのマシンで同じパスワードで設定してやるくらいしたほうがいいんだけど。まあ仕事でやるのとは別なんで)
これでMacのホームで.ssh/id_rsa.pubが生成できますから、これをサーバー側に送ってやり(scpがいいでしょう)、サーバー側のリポジトリを公開するユーザーのホーム/.ssh/authorized_keysにアペンドしてやりましょう。(くれぐれもコピーはしないように!1マシン=1行で登録されてますから、コピーなんてするとほかのマシンの設定が消えてしまいます。なお最初の登録時には.ssh/自体存在しないことがありますが、そのときは自分で作成します)


1.まずgitサーバーのマシンでリポジトリの作成(サーバーのgitアカウントで実行)
gitアカウントのホームに作ります。

$ mkdir project.git
$ cd project.git  ←<リポジトリを作成するディレクトリ>
$ git init ←これ不要かもしれません。クライアントが必要なだけの気もする。

.git/というリポジトリが保存されるディレクトリが作成されるだけなので、同じ階層に共有するリソースを作成する。
ここで注意ですが、ここで生成されるのはgitリポジトリであり、ファイル本体はこのリポジトリ内にあり、素で見てもファイル名なんかは見えません。gitサーバーでもリポジトリ内のファイルがどうなってるかみたいなら、別アカウントでこのリポジトリのクローンを作ってやりましょう。

2.クライアント側の環境設定をする
各クライアント(まずはMacです)で以下のコマンドを実行します。homeディレクトリの.gitconfigというファイルに登録されます。(EclipseではGUIで行いますが、登録内容は同じです)

$ git config --global user.name "Hoge Hoge" ←当該リソースを触った人です
$ git config --global user.email hoge@home.com
$ git config --global core.qutepath false (ファイル名の文字化けを防ぐ)// 別のより新しい記事ではこの記載がない
$ git config --global core.editor "'C:/Program Files/sakura/sakura.exe’ -code=4" (デフォルトのエディタを設定 なければviがデフォルトになる)

3.クライアントのマシンでリポジトリのクローンを作成する。
今回は1.でリポジトリ名をproject.gitとしたので、何となく作業用ファイルを置く場所も「project」にしてしまいました。そのあたりは実際に使うときに変えてください。

$ cd <クローンを作成するディレクトリ>
$ git init ←記憶が明確でないけど必要な気がする
(20131016:結果的には同じですが間違えてました。git initいりません。)
$ mkdir project     // クローンを作成するディレクトリ
$ git clone git@<ホストアドレス>:/home/git/project.git project

これでsshによりgitサーバーからリポジトリのクローンがローカルに作られます。(ただ最初は空っぽですが)サーバーの指定がgitのsshで直接やる一番原始的なコマンドで、本当はhttp, httpsでスマートにやりたいんですが、そのためにはApatch等の設定が大変なので、それはまた今度ということに)
実は今回いろいろ試しながらやってたので、もしかしたらMacやUbuntuではcloneやるまえに、git initする必要があると思います。EclipseだとGUIが勝手にやってしまってるかもしれないんで。cloneする前に、.git/というリポジトリ情報を保存するエリアを作成しておく必要がある気がします。(1.のサーバー側準備でgit initコマンドしてますが、今から調べるとこれ意味なかったような状態になっており、施行錯誤してるときにクライアントで先にgiti initやった記憶があります。)


4.クライアント側で作業をする

さてクローンが無事できたので(最初だと空っぽだけど)、最初のファイルを作ります。

$ vi text.txt

適当にテキストをいれ、これをクライアント側のローカル・リポジトリに追加しましょう。

$ git add text.txt ←最初の1回は当該ファイルを管理対象に追加する指定が必要です
$ git commit ←ローカル・リポジトリへのcommitです。エディタでコメントを求められます。正式にはコミットするファイルをこのあとに引数で与えます。


5.gitサーバのリポジトリにローカルを反映させます。

$ git push origin master

(originってなんだ?ってとこですが、gitサーバーのリポジトリを示しています。一度、cloneコマンドを行った時にアドレスが記録されているのでこれでいいんですが、全部書くと以下のようになります。

$ git push git@<ホストアドレス>:/home/git/project.git master

最後のmasterはブランチ名です。masterは当然デフォルトのやつです。Subversionでいうところのtrunkにあたります。)
2回目以降は単に以下でいけます。それはそれでどこに作用するのかわからないので怖いんですが。

$ git push


6.別のクライアントにローカルリポジトリを作成する

ここからが本番です。別のマシン(今回は別のUbuntuでいきます。Windowsは慣れてからで)にローカルリポジトリを作成します。
まず2.の環境設定をします。わざとユーザー名は変えておきましよう。(Hiroyuki Maeda2)後で誰が変更したのか確認できるようにです。
次に、3.の手順でクローン・リポジトリを作成します。すると今度は3.でcloneを作ったところでリポジトリに追加したtext.txtが作業エリアに登場してきます。


7.別のクライアントでファイルを編集

text.txtに2行目を追加します。それをコミットしてpushします。

$ vi etxt.txt
$ git add text.txt
$ git commit ←ここでコミットログ求められます
$ git push origin master


7.最初のクライアントでgitサーバーのリポジトリを取得

さて2番目のクライアントがファイルを変更しました。1番目のクライアントでそれを取得します。

$ git pull ←必要ならoriginやmasterの情報を付加します
シェルには何やらファイルが変更されたとのメッセージが。
確認すると、確かに2行目が追加されています。

$ git log

これでコミットログを確認すると確かにログが表示されます。


8.コミットログやファイル本体に日本語使うとどうなる?

さて実際に使いこもうと思うと、最初の難関が日本語です。(正確には文字コード)
UbuntuなんかはUTF-8だし、MacはSJIS(と思ったんですがsnow Lepord以降はUTF-8のようでした)、Widnowsは今はUnicode(ほとんどUTF-8)です。

試してみたら、Ubuntu側で日本語でログやらファイルを編集しても、Macでは無事よめちゃいます??自動で文字コード変換してる? ちょっとこれ以上はWindowsも入れてみないとなんともわかりません。


9.Windowsでローカル・リポジトリを作成

さて今度はWindowsです。eclipseがEGitをインストール済みなので、これを使います。importでGitを取り込めますが、サーバ側がsshの設定しかしてないので、プロトロコルは当然sshでいきます。
取り込んでみると、ファイル自体はやはりUTF-8でした。(ただ鍵ファイルの設定がみあたらない。もしかして鍵なしのssHでいってしまったかも)
コミットログのヒストリを見てみると、ちゃんと誰が修正したかもわかります。(このために、ユーザー名を2つのクライアントで変えておきました)なおローカル・リポジトリはEclipseのworkspace以下に各プロジェクトが保存されていますが、当該プロジェクト名フォルダ直下に「.git」フォルダが作られていますので、そこで管理されています。
ところでEclipseだとuser.nameとかどこで管理しているのか?それはPreference → Team → Git → Configurationのところでkeyとvalueの設定をするところがあります。ここにuse.nameとかuser.emailとか設定します。注意するのがcore.autocrlfで、これいつもEclipse起動時にDialogがでて気になりググってみたら、push/pull時に改行コードを自動的にCRLFにしてしまうかどうかという設定でした。当然、falseにしておきます。(おそらくこれはWindows独特の設定だと思います。Windowsだけは改行が昔からCRLFですが、LinuxやMacはLFだけですから。)
あと注意が必要なのが、commitとpush/pullのやりかたです。基本右クリックで表示されるメニュー内のTeamサブメニューでやるんですが、ファイルを選択したときはcommitしかでません。プロジェクトで右クリックするとpush/pullのサブメニューがでてきます。(当たり前といえば、当たり前ですが)



疑問 git pushでローカルのリポジトリがサーバーに送られるが、その時に衝突が起きた場合どうなるのか?

Windows側でファイルを更新、pushしてからMac側でその更新をpullして確認。その後、Ubuntu側で(最新のpullをする前に)独自の修正をしてpushしようとしたらサーバーからrejectされました。
一番いいのは作業する前に

$ git fetch
$ git diff FETCH_HEAD

を行い、自分のローカルリポジトリをサーバー上のものと調べてること。

$ git merge FETCH_HEAD

もしpushしてrejectされるようなら、上記を行い手作業でマージして差分を解消してからpushしなおしになります。(先にpullしてサーバーとローカルリポジトリの同期をしてから、pushしなおさないといけないかもしれません。この方法だと最後にマージのログがヒストリに残りました。)一番簡単なのは、自分の作業用ファイルをどっかにおいておいて、pullして作業環境をサーバとあわせ、さきほど別のところにおいておいたファイルを見ながら修正することでしょうね。

実際にUbuntu側で問題を解決しpushしたあと、Windows側でpullしてhistoryを見てみた画像です。なんか以下にもmergeやったよ、という記録まで残ってます。


最後に日本語の文字コードについて。基本、UTF-8が問題でないようです。ファイル名もUTF-8なら問題ありません。ただところどころ使ってる環境によって日本語がファイル名のログ表示が化けるものがありますが、結果は大丈夫です。(このあたりはまだまだだと感じました)WindowsのGit GUIでも日本語ファイル名の扱いに問題がでるようですし、一番問題がなさそうながどのOSでもEclipseのようです。CUIでやるのが基本のようですが、いまどきそれはつらい。(Git作ったLinusはバリバリのコマンド入力の人らしいし、このあたりはだいぶ時代に遅れています。)



0 件のコメント:

コメントを投稿