Gitの使い方¶
ここでは、複数開発者がソースコードを共同で作成する現場を想定し、典型的な作業手順を整理します。
構成管理者の初期作業¶
共有リポジトリの作成¶
分散型バージョン管理でも、マスターとなるリポジトリを1つ設けるのが定番です。そこで、共有リポジトリを設けます。
共有リポジトリはhttp/https/ssh/gitプロトコルでアクセスできるサーバーに置きます。
開発者がLinuxを使っているなら、sshプロトコルを使った利用が一番簡単かもしれません。
http/httpsプロトコルの場合、参照は簡単ですが変更のpushには仕掛けが必要となります(WebDAVまたはCGI)。
gitプロトコルの場合、gitサーバーをサービス起動させます。
詳細は今後記述予定
空のリポジトリ¶
空のリポジトリをcloneしてファイルを登録してpushすると、ブランチ指定が必要になります。なので、管理者が初期リポジトリを作成するときはファイルを少なくても1つ登録した状態にしておくのがよいです。
無視ファイルリストの作成¶
プロジェクトで決めた無視ファイルの定義を作成しておきます。
開発に使用するツール特有のバックアップファイル、一時ファイル、個人ファイルや、コンパイルにより生成される中間ファイルなど、リポジトリに登録して管理するのに不都合なファイルはあらかじめパターン定義しておきます。
- #で始まる行はコメント
- !で始まる行は残りのパターンを否定
- /で終わる名前はディレクトリにのみ合致
- /で始まる名前はルートディレクトリから指定
- /がどこにも含まれない名前はシェルのglobパターンでファイル名のベース部分に合致
パターン | 内容 |
---|---|
*~ | ファイル名の末尾に'~'がある全て |
*.[ao] | 拡張子がaまたはoのファイル |
tango/ | tangoディレクトリは無視 |
victor | ファイル名victorは無視 |
!*.sierra | 拡張子sierraのファイルは無視しない |
- http://gitignore.io/
OS、言語、統合開発環境(IDE)の名前を入力すると、その典型的な無視ファイルリストを生成するWebアプリケーションです。
開発者の作業¶
記載見直し中 |
開発者の作業は大きくは次となります。
- 共有リポジトリをcloneして個人リポジトリを作成する
- 個人リポジトリに変更を加える
- 個人リポジトリの変更を共有リポジトリに登録する(トピックブランチ)
- (レビュー者が内容を確認する)
- トピックブランチの内容をmasterブランチにマージする
個人リポジトリはいくつ作ってもよいので、気軽に作成するのがお勧めです。
個人リポジトリを変更する分には共有リポジトリには影響を与えないので、好きなだけいじりまわせます。試行錯誤のブランチをいくつも作成したり、いらない変更を破棄したり、
ここでは、リポジトリ運用ポリシーがトピックブランチを要求する場合での作業を記載します。
共有リポジトリをcloneして個人リポジトリを作成する¶
cloneすることで、共有リポジトリのその時点のコピーが作成されます。一緒に作業ツリーも展開されます。
手順¶
例えば開発タスク#194に基づく変更を加える場合、共有リポジトリのmasterブランチをクローンし、トピックブランチを作成してそこへ移動します。
トピックブランチの命名規則はここではfeature/#チケット番号
とします。ブランチ名でのスラッシュはディレクトリ区切りではなく、単なる文字として扱われます。
- 共有リポジトリのmasterをクローン
~$ mkdir work ~$ cd work work$ git clone http://repo.example.com/git/golf work$ ls golf work$ cd golf golf$ git branch -a * master golf$
- トピックブランチを作成してそこに移動
golf$ git checkout -b topic/#194 golf$ git branch * topic/#194 master golf$
個人リポジトリに変更を加える¶
gitは、作業ディレクトリの変更を直接リポジトリにコミットするのではなく、作業ツリーの変更をいったんインデックス(ステージングエリア)と呼ばれる領域に上げて、ついでインデックスの内容をリポジトリにコミットします。
subversionに慣れている人が感でgitを使うと、このあたりが混乱するのではと思います。
変更したファイルをインデックスに上げる¶
golf$ git add src/golf/Model.java golf$ git add conf/golf/Model.conf golf$
新規ファイル、変更ファイルはgit addでインデックスに上げます。
ファイルの削除¶
ファイルを削除するときは、git rmでインデックスに削除指示を上げます。
ファイルの移動(名前変更)¶
ファイルを移動・名前を変更するときは、git mvでインデックスに移動指示を上げます。
コミットする内容を事前確認する¶
インデックスに上げた各種変更を確認するときは、git diff --cachedを実行します。
インデックスに上げられた変更内容を一括コミットする¶
インデックスに上げられた内容を一括コミットするときは、git commitを実行します。
個人リポジトリの変更を共有リポジトリに登録する(トピックブランチ)¶
トピックブランチにおいて変更に関する一連の作業が完了した段階で、その変更をトピックブランチとして共有リポジトリに登録します。
トピックブランチは個人リポジトリで作成したので、最初はリモートへの対応付けを明示的に指定してpushします。
golf$ git push origin topic/#194 :
originは、このリポジトリをcloneした元の共有リポジトリを指しているので、そこへブランチを指定してpushします。
実はブランチ名の指定は省略形となっています。実際には、ローカルのブランチ名:リモートのブランチ名 と指定します。コロンのどちらかは省略可能で、右側を省略する際はコロンも省略可能です。省略時は同じブランチ名が指定されたとして扱います。この例では、ローカルにあるブランチ「topic/#194」を、リモートにブランチ名「topic/#194」としてpushすることを指示しています。
トピックブランチの内容をmasterブランチにマージする¶
masterブランチへ移動し、最新版を反映¶
最初にmasterブランチを最新にしておきます。
golf$ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'. golf$ git pull : golf$ git merge
ここで、ブランチに変更(作業途中の未コミットファイルなど)があるとcheckoutでブランチを移動できません。作業完了させてきれいにしてからブランチを変えてください。
個人リポジトリ上でトピックブランチの変更をmasterブランチにマージ¶
golf$ git merge --no-ff topic/#194
--no-ff
を指定するかどうかは運用のルールによります。マージしたことを記録に残す運用であれば指定します。デフォルトは--ff
なのでブランチで作業した個々のコミットがそのままmasterブランチに対するコミットのように見えます(履歴が一本化)。
トピックブランチの削除¶
記念に残しておいてもよいですが、特に共有リポジトリ側はトピックブランチが増えてくると手間なので用済みになったら削除します。
ローカルのトピックブランチの削除¶
golf$ git branch --delete topic/#194 Deleted branch topic/#194 (was 1b0c4fa).
- --delete は、省略形 -d でも可
- マージしていないブランチはこのオプション指定では削除できない
共有リポジトリ(リモート)のトピックブランチの削除¶
golf$ git push --delete origin topic/#194 To http://www.torutk.com:8008/git/swe.primus - [deleted] topic/#194
または、git push origin :topic/#194
マージ済みかどうかを調べる¶
メインのブランチ(トピックブランチをマージする先)をチェックアウトし、次のコマンドを実施するとマージ済みのブランチが表示されます。
$ git branch --merged topic/#194 * master
マージしていないブランチを表示することもできます。
$ git branch --no-merged topic/#181 topic/#197 hello_bra
トピックブランチ作業中にmasterが進んでしまった¶
masterからトピックブランチを生成し、開発作業をしている間に、masterのコミットがどんどん進んでしまい、ローカルリポジトリでトピックブランチを最新masterにマージしようとすると多数のコンフリクトや矛盾が発生します。
対処方法がいくつか想定できます。
- 最新masterをトピックブランチにマージし、最新masterを反映したトピックブランチにアップデート
- トピックブランチをrebase
どちらも多数のコンフリクト、矛盾をトピックブランチ開発者が整合させます。
こんなことできないかな?¶
ブランチを変更する¶
masterブランチを別なブランチとして、新たにmasterブランチを開始したい¶
まだ変更をコミットしていないならば、masterブランチのHEADでブランチを作成し、ブランチにチェックアウトしてから変更をコミットします。
もしmasterブランチに変更をコミットしていたら、Gitのブランチ名を変更するコマンドで対応できます。
- 既存のmasterブランチを別名に変更します。
- 本来masterとしたい出発点のレビジョンでブランチmasterを作成します。
ブランチの変更をなしにする¶
変更した管理下のファイルを元に戻す¶
git reset --hard HEAD
- --hard はステージ、作業ディレクトリの変更も戻す
未追跡のファイルとディレクトリを削除する¶
git clean -fd
- -f は削除実行指定
- -d はディレクトリを削除対象
コミットを戻す¶
git reset --hard HEAD^
- HEADにハット記号(^)を1つ付けた場合、HEADの一つ前のコミットに戻す
マシン毎に一部が異なるファイルの管理方法¶
例えば、設定ファイルなどで使用するマシンにより一部項目に異なる記述が必要となる場合の管理方法を模索します。
案をいくつか列挙すると
- 1. 記述を変更する必要のあるマシン毎にブランチを作成
- 2. マシン毎の記述をファイル名を変更してリポジトリに登録
- 3. 設定のテンプレートファイルのみリポジトリに登録
1. のブランチは、固有設定を持つマシンが増えるとブランチがそれに応じて増えます。また、マシンが追加・変更・削除になるとブランチの管理もそれに追従する必要があります。(ブランチ一覧に数十、数百がでるようなことは・・・)
2. は、config.yml に対して、config-a.yml, config-b.yml ... と固有設定のマシンごとに名前をかえて管理することになります。これもファイル数が増えるだけでなく、共通部分の設定が変更になった場合にすべてのファイルに変更を反映する作業が発生します。
1.と2.は、固有設定のバリエーションをすべてリポジトリに置く管理方法です。それに対して、3.は固有設定を排除し共通設定を1つだけテンプレートとしてリポジトリに置く方法となります。config-template.ymlを1つ管理し、各マシンではconfig-template.ymlを名前変更して固有設定を記述したconfig.ymlを置きます。テンプレートの共有記述に変更があった場合は、展開されたファイルに再度固有記述を反映させる必要があります。