Git(ギット)によるソースファイル管理

1        はじめに

1.1      バージョン管理の必要性

1.1.1  更新履歴の記録

ソフトウェアを開発していると,以前は動いていたのに,変更したら動かなくなったということが起こる.また,トラブルやミスにより成果物を失ってしまうこともある.ソースコードの更新履歴を保存しておくことにより,過去のバージョンのソースコードを閲覧したり,開発中のソフトウェアをそのバージョンに戻したりできる.

1.1.2  ソフトウェアの共同開発

一般にソフトウェア開発は,複数の開発者が参加するプロジェクトとして行われる.この場合,異なる開発者が同じソースコードを編集するということが起こり得る.同一のファイルを複数の人が同時に編集すると,編集内容に矛盾が発生したり,最新バージョンがどれだかわからなくなったりする.ソースコードの更新履歴を管理することにより,常に最新バージョンが明らかになり,異なる開発者による編集内容の統合(マージ)や競合(コンフリクト)の調停を行うことができる.

1.2      VCS (Version Control System)

ソースコードの履歴管理を行うソフトウェアをVCS (Version Control System) – バージョン管理システムと呼ぶ.VCSにおいて,更新履歴は以前のバージョンとの差分(変更点)によって管理される.この差分を保持するディレクトリをリポジトリ (Repository, Repo) と呼ぶ.

VCSとして,古くからSCCS (Source Code Control System) やRCS (Revision Control System) が使われてきた.リポジトリを持つものとしては,CVS (Concurrent Versions System) やSVN (Subversion) がある.また,Microsoft Visual StudioにもVSS (Visual Source Safe) というVCSが用意されている.これらはソースコードを単一のリポジトリで管理する集中型のVCSである.

これに対し分散型のVCS,いわゆるDVCS (Distributed VCS) も使われている,これは開発者間で共有するリポジトリの他に,個々の開発者も専用のリポジトリを持つ.この場合,開発者が個々に履歴管理を行い,結果を共有のリポジトリに反映することになる.これにはGitやMercurialなどがある.

VCS/DVCSによるバージョン管理を行う場合,開発者は最初にリポジトリからソースファイルを取り出して,手元(のマシンやディレクトリ)に保存する.この操作をチェックアウトという.また,手元のファイルを編集してリポジトリを更新する操作をチェックインという.なおGitなどのDVCSでは,この操作は手元のリポジトリに対するものと共有のリポジトリに対するものの二段階になる.

手元のファイルを編集しているうちに他の開発者がチェックインしている可能性があるので,ファイルの編集を始める前にはリポジトリから最新のソースコードを取り出して,手元のファイルを更新すべきである.この操作をアップデートという.また,自分がチェックインする前にも適宜アップデートを行い,他の開発者の編集内容と自分の編集内容を統合しておく.

1.3      Git

Linuxのカーネル開発で使われているDVCS.Windowsでも使える.GitHub (http://github.com/) のような公開リポジトリ(非公開にすることもできるけど有料)もある.

2        Git のインストール

たいていのLinuxディトリビューションはGitのパッケージを用意している.Mac OS Xにもgitコマンドは最初から入っている(Xcode 4が対応している).Windowsについてはgitコマンドやそのためのシェル,及びGUIが入手可能である.詳しくはGitのホームページ http://git-scm.com/ を参照のこと.

3        ローカルリポジトリの作成

3.1      初期設定

最初に開発者の名前とメールアドレスを登録する.これはgitコマンドを使うすべてのマシンで最初に一度だけやっておく必要がある.“Your name” には開発者の名前,user@center.wakayama-u.ac.jpには開発者のメールアドレスを設定する.これらはcommit(後述)するたびに履歴情報に埋め込まれる.

git config --global user.name "Your name"
git config --global user.email user@center.wakayama-u.ac.jp

ここで標準的に使用するテキストエディタを指定することもできる.指定しなければvimが起動する.

git config --global core.editor emacs

3.2      git init – リポジトリの初期化

履歴管理をおこなうプロジェクトのディレクトリ(フォルダ)にcdする.Macではcdtoというツールをインストールしておくと便利である.Windowsでは,Gitをインストールしていればフォルダの右クリックで “Git Bash Here” というメニューが現れる.そこで以下のコマンドを実行する.

git init

3.3      .gitignoreファイル – 履歴管理しないファイルの指定

プロジェクトのディレクトリの中にある履歴の管理を行わないファイル(テキストファイルでないものやサイズが巨大なファイル,他人には見られたくないファイルなど)を .gitignoreというファイルに列挙してプロジェクトのディレクトリに置く.このファイルの書式は自分で調べること.

3.4      git add – 履歴管理するファイルの追加

履歴管理を行うファイルをリポジトリに追加(登録)するには git addコマンドを実行する.

git add ファイル名 …

そのディレクトリ以下のすべての(.gitignoreに登録していない)ファイルを追加するには,カレントディレクトリを表す .(ピリオド)を指定すればよい.

git add .

ファイルの追加を取り消すにはgit rmコマンドを実行する.–cached というオプションを付けないとファイル自体も削除されてしまうので注意.

git rm --cached ファイル名 …

3.5      git rm / git mv – 履歴管理しているファイルの削除と移動

git addコマンドで追加したファイルはGitの管理下にあるので,不用意に削除したり移動したりしてはいけない.ファイルの削除や移動はgit rmコマンドやgit mvコマンドを使って行う.

git mv 元のファイル名 変更後のファイル名/移動先
git rm ファイル名 …

3.6      git commit – 履歴の登録

ファイルの追加が終わったら,commitしてローカルリポジトリに登録する.-mオプションで指定している “first commit” はこのcommitに付けるコメントである.

git commit -m "first commit"

4        リモートリポジトリの作成

VCSは複数の開発者による共同開発を支援する.Gitの場合,同一のコンピュータなら,前章で作成したリポジトリをgit cloneコマンド(後述)でコピーして共同開発を行う.Gitはさらに,ネットワークを介して異なるマシン間で共同開発する場合にも使用することができる.その場合はリポジトリだけを特定のコンピュータ上に作成し(リモートリポジトリ),それを共有する方法を採ることもできる.

4.1      ssh クライアント

4.1.1  遠隔ログイン

Windows版のGitはMinGWやCygwinで動いているので,その端末ウィンドウ(シェル)でsshコマンドが使える.システム情報学センターのサーバhost.wakayama-u.ac.jpにログインするには下記のようにする.

ssh user@host.wakayama-u.ac.jp

このほかのクライアントとして,WindowsにはTera TermやPuTTYがある.Tera Term は余計なものをインストールしない「コンパクトインストール」を個人的におすすめする.PuTTYには日本語化された「ごった煮版」がある.

4.1.2  ファイル転送

これもGitをインストールしていれば,シェルからscpコマンドやsftpコマンドが使える.このほかのクライアントとして,WindowsではWinSCPが使える.Macにはもともとscpコマンドやsftpコマンドが入っているが,Cyberduckも使いやすい.またLinux/Windows/Macで使えるFileZillaというクライアントもある.

4.2      鍵作成(この作業は飛ばしても構わない)

鍵はssh-keygenコマンドで作成できる.公開鍵と秘密鍵を作成し,公開鍵をログイン先のコンピュータに保存する.保存の仕方はログイン先に依存するが,システム情報学センターのサーバの場合はホームディレクトリにある .sshという(不可視)ディレクトリ内に置いたauthorized_keysというファイルに追加する(このファイルが無ければ新規作成する).これは単に次のコマンドを実行すればよい.

cat 公開鍵ファイル >> ~/.ssh/authorized_keys

なお,鍵を作成する際にパスフレーズ(鍵を開くためのパスワード)を付けないでおくと,遠隔ログインの際にパスフレーズの入力を求められなくなる.秘密鍵を持ったクライアントからしかログインできないので他人が勝手にログインできるわけではないが,秘密鍵が漏れて(他人に知られて)しまうと危険なので,パスフレーズは付けておくべきである.

4.3      空のリポジトリの作成

まずsshクライアントを使ってシステム情報学センターのサーバhost.wakayama-u.ac.jpに遠隔ログインする.

リポジトリをuserというユーザのホームディレクトリのgitというディレクトリに作る場合は,下記のようにする.myproject は自分が作成するプロジェクトの名前.

mkdir ~user/git/myproject.git
git init --bare ~user/git/myproject.git

リポジトリだけを置く(ソースファイルなどは置かない)ので,このgit initには –bareオプションを付ける.リポジトリを自分のホームディレクトリ直下に作るなら,“~user/git” は “~” だけでよい.

この後ログアウトする.以後はリポジトリを削除するときくらいしかログインすることはないと思う.

4.4      git remote add – リモートリポジトリの登録

ローカルリポジトリにgit commitした内容をリモートリポジトリに反映するには,最初に手元のプロジェクトのディレクトリでgit remote addコマンドを実行して,リモートリポジトリを登録する.

git remote add origin ssh://user@host.wakayama-u.ac.jp/~user/git/myproject.git

このコマンドはhost.wakayama-u.ac.jpの ~user/git/myproject.gitというディレクトリにあるリポジトリを,originという名前のリモートリポジトリとしてローカルリポジトリに登録する.

ローカルリポジトリの内容をリモートリポジトリに反映するには,git pushコマンドを使う.

git push -u origin master

これはoriginで表されるリモートリポジトリにローカルリポジトリのmasterというブランチ(後述)の内容を反映する.一度git pushコマンドに -uオプションを付けて実行すれば,以後git pushコマンドを実行するときに引数の “origin master” を省略できる.

git push

5        日常の手順

5.1      git clone – リポジトリのコピー

別のコンピュータで作業をする場合や他人のプロジェクトを取り出す場合など,既にリモートリポジトリに反映されている内容を手元にコピーするには,git cloneコマンドを用いる.これは最初に一度だけやればよい.

git clone ssh://user@host.wakayama-u.ac.jp/~user/git/myproject.git

これでプロジェクトのディレクトリが手元に丸々コピーされる.

5.2      git pull – アップデート

手元にプロジェクトのコピーが既にある場合は,そのファイルを編集する前に,git pullコマンドを使ってリモートリポジトリの内容をローカルリポジトリに反映しておく.

git pull

このとき競合(コンフリクト)が発生していたら,他の開発者と相談の上,どう対応するか考える.詳細はgit logコマンドやgit showコマンドで調べることができる.

5.3      git commit – 履歴の登録

ファイルの編集が終わったらcommitしてローカルリポジトリに履歴を登録する.-aオプションを付ければ,変更されたファイルに対してgit addも自動的に実行してくれる.

git commit -a -m "コメント"

-m オプションで指定する “コメント” には,どういう編集や変更をおこなったかを記録しておく.-mオプションを省略した場合は,初期設定でテキストエディタを指定していなければ,vimというテキストエディタが起動する.vimのもととなったviはemacsと双璧をなすUnix/Linux伝統のテキストエディタなので,使い方は覚えておいて損はない.なお,コメントを指定しないとcommitされない.

5.4      commit の取り消し

commitを取り消す場合はgit resetコマンドを使う.このとき,commitしたことだけを取り消してファイル自体はそのままにしておくなら –softオプションを指定する.

git reset --soft HEAD^

–hardオプションを指定すれば,編集したファイルも一緒にcommit前に戻す.

git reset --hard HEAD^

なお,直前のcommit内容を捨てて現在の編集内容でcommitを新たにやり直すには,git commitに –amendオプションを追加する.

git commit --amend -a -m "やり直した内容に対するコメント"

5.5      git push – リモートリポジトリへの反映

commitした内容をリモートリポジトリに反映して他の人と共有するには,次のコマンドを用いる.

git push

6        ブランチ

プロジェクトに対して大幅に変更を加える場合には,一旦そのリポジトリを枝分かれさせて,それに変更を加えてから,後で変更点をもとのリポジトリに統合(マージ)するという手順を取る.

6.1      ブランチの作成

リポジトリを枝分かれさせるには,git branchコマンドを使う.枝分かれさせたリポジトリをブランチと呼ぶ.newbranchは枝分かれさせたブランチに付ける名前.

git branch newbranch

ブランチ名(ここではnewbranch)を省略すると,現在のリポジトリにあるブランチの一覧が表示される.もともとあったブランチはmasterになっているはず.

6.2      ブランチの切り替え

あるブランチに対して変更を加える時は,git checkoutコマンドを使ってそのブランチに切り替える.

git checkout newbranch

このブランチに加えた変更は,他のブランチには反映されない.例えば,ここでgit checkout masterコマンドによってmasterブランチに切り替えると,変更したはずのファイルが元に戻っている.

なお,git checkoutコマンドに -bオプションを付ければ,新しいブランチを作ってそのブランチに切り替える操作を一度にできる.

git checkout -b newbranch

このコマンドは,次の二つのコマンドと同じである.

git branch newbranch
git checkout newbranch

6.3      リモートリポジトリにブランチを作成

あるブランチで行った変更は,git pushによって他のブランチや最初のブランチであるmasterには反映できない.ブランチはリモートリポジトリの対応するブランチにgit pushする.

git commit -am "コメント"
git push origin newbranch

このgit pushを -uオプションを付けて実行すれば,以後git pushコマンドを実行するときに引数の “origin newbranch” を省略できる.

6.4      ブランチのマージ

現在のブランチで行った変更をmasterブランチに反映するには,masterブランチに切り替えてからそのブランチをマージする.リモートブランチの変更内容をマージする場合は,この前にgit pullする.

git checkout master
git merge newbranch

これをリモートリポジトリにも反映するには,git pushコマンドを使う.

git push

7        こういうときは

7.1      関係ないファイルをgit addしてしまった

git rm --cached ファイル …

7.2      git add自体を取り消したい

git reset HEAD

7.3      関係ないファイル(.gitignoreにも登録されていない)を削除したい

git clean -f

このとき必要なファイルまで消してしまう可能性があるので,事前に次のコマンドでチェックする.

git clean --dry-run

7.4      前のcommitを捨ててもう一度commitし直したい

git commit --amend -am "コメント"

7.5      ファイルを編集前に戻したい

rm ファイル
git checkout ファイル

7.6      全部のファイルを直前にcommitしたときに戻したい

git reset –hard HEAD

–hardオプションを付けると変更内容を取り戻すことはできないので注意すること.

7.7      現在の編集内容をそのままにして直前のcommitを取り消したい

git reset --soft HEAD^

7.8      直前のcommit自体を取り消して現在の編集内容をその前に戻したい

git reset --hard HEAD^

7.9      直前のcommitからの変更内容を見る

git diff

7.10    直前にcommitした内容を見る

git show

7.11    履歴を見る(-pオプションを付けると変更内容も表示する)

git log