SYNOPSIS

git *

解説

このチュートリアルでは git に新しいプロジェクトソースをインポートする方法と、 そこに変更を加える方法、そして他の開発者と変更を共有する方法を説明します。

もしあなたの主な目的がプロジェクトの変更を取得することであるなら (例えば最新バージョンのソースを取得してテストするなど)、 Git ユーザマニュアル の最初の2章から始める方が 良いかもしれません。

まず最初に、マニュアルの参照方法を説明します。例えば "git log" コマンドのマニュアル は以下の方法で取得できます。

$ man git-log

もしくは:

$ git help log

もう一つの方法としてgit-helpコマンドを使用する方法があります。 詳細についてはgit-help(1) をご覧下さい。

どんな操作をするよりも前に git に自分の氏名とメールアドレスを紹介するのは良いアイデアです。 最も簡単な方法は以下の通りです:

$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email [email protected]

新規プロジェクトのインポート

あなたの作品が入った tarball project.tar.gz があるとします。 あなたは以下のようにしてそれを git のリビジョン管理下に置くことができます。

$ tar xzf project.tar.gz
$ cd project
$ git init

この操作により git は以下のメッセージを表示するでしょう。

Initialized empty Git repository in .git/

これで作業ディレクトリの初期化が完了しました。そして、あなたは ".git" という名前の ディレクトリが作成されたことに気がつくでしょう。

次に、git-add を使用して カレントディレクトリ下の すべてのファイルのスナップショットを取得するように git に依頼します ('.'があることに注意):

$ git add .

このスナップショットは "索引(index)" と呼ばれる一時エリアに 格納されます。git-commit を用いるとリポジトリに索引の 中身を永続的に格納させることができます:

$ git commit

コミットコマンドを実行すると、コミットメッセージの入力が求められます。 その後、プロジェクトの最初のバージョンが git に格納させます。

変更の実施

いくつかのファイルを変更した後、更新した内容を索引に追加します:

$ git add file1 file2 file3

これでコミットする準備ができました。git-diff を --cached オプション付きで 実行するとコミットされる内容を確認できます:

$ git diff --cached

(--cached を指定しない場合、git-diff は修正されているがまだ索引に 追加されていない変更を表示します。) git-status を使用すると 簡潔なまとめを表示することもできます。

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   file1
#       modified:   file2
#       modified:   file3
#

さらに変更が必要な場合は、それを行い、新しく変更した内容を索引に追加します。 最後に、変更をコミットします:

$ git commit

この操作を行なうとエディタが起動され、コミットメッセージの入力が促されます。 メッセージを入力しエディタを終了するとプロジェクトの新しいバージョンが記録されます。

コミットのもう1つの方法として、事前に git-add を実行する代わりに、以下のようにすることもできます。

$ git commit -a

この方法では変更ファイル(ただし新規ファイルは除く)を自動的に検出し、 それらを索引に追加し、コミットするという操作を纏めて実行します。

コミットメッセージに関する注意: 必須ではありませんが、格納メッセージを 次のようにするのは良い考えです。1行の短文(50文字未満)で変更のサマリを書き、 その後に空白行を挟んで、最後により綿密な記述をまとめる。 そうすることで、例えばコミットした内容を E-Mail に変換するツールにて、 Subjectに最初の行を使用し、残りの行を本文にすることができます。

git はファイルではなくコンテンツを追跡する

多くのリビジョン管理システムでは add コマンドは新規ファイルを追跡対象に加える 役目をします。git の add コマンドは、よりシンプルでパワフルです: git-add は新規ファイルと新しい変更ファイルの両方に対して使用され、 どちらの場合にも指定したファイルのスナップショットをとり、索引にその中身を 登録し、次のコミットに含める項目の準備をします。

プロジェクトの履歴を参照する

どんな時でも、次のコマンドを実行することで変更の履歴をみることができます。

$ git log

各ステップの完全な差分を参照したい時は、次のようにします。

$ git log -p

修正したファイルの名前とログメッセージを参照したい時は、次のようにします。

$ git log --stat --summary

ブランチ管理

git は1つのリポジトリ内に複数のブランチを作成することができます。 "experimental" という名前の新しいブランチを作成するには次のようにします。

$ git branch experimental

次のコマンドを実行すると

$ git branch

存在する全てのブランチのリストが表示されます:

  experimental
* master

"experimental" ブランチは今あなたが作成したものです、そして、 "master" ブランチは自動的に作成されたデフォルトブランチです。 "*" のマークは現在作業中のブランチを指しています。; 以下のコマンド

$ git checkout experimental

を打つと experimental ブランチにスイッチします。 さて、ファイルを編集し、コミットし、master ブランチに戻ってください:

(edit file)
$ git commit -a
$ git checkout master

experimental ブランチで変更した後、master ブランチに戻っている為、 変更した内容がもはや見えなくなっていることを確認してください。

あなたは master ブランチ上で別の変更をすることができます:

(edit file)
$ git commit -a

この時点で2つのブランチは分岐しました。それぞれ異なる変更が行なわれています。 experimental の変更を master にマージするには、以下のようにします。

$ git merge experimental

変更がコンフリクト(競合)しない場合は、これでマージ完了です。 コンフリクトがある時は、マーカーが問題のあるファイル内に残り、 コンフリクトを示すでしょう。そして、

$ git diff

を行うとマーカーの位置を示します。 コンフリクトを解消する為に一度ファイルを編集し、以下のようにすると

$ git commit -a

マージした結果がコミットされます。 マージした結果は GUI ツールで確認することができます。

$ gitk

を実行すると、実行結果の履歴がグラフ表示されます。

この時点で、experimental ブランチを削除できるようになりました。 次のようにして行います。

$ git branch -d experimental

このコマンドは、experimental ブランチで行った変更が既に現在のブランチに 含まれていることを確認してからブランチを削除します。

マージしていないブランチを強制的に削除したい時は (例えば crazy-idea ブランチで変更を行い、次に、その変更が間違いであると思ったなら) オプションを -d ではなく -D に変更して実行します。

$ git branch -D crazy-idea

ブランチは手軽で簡単です。何かを試す時にはとても便利です。

共同開発における git の利用

アリスが /home/alice/project にある git リポジトリで新規プロジェクトを 開始したとします。同じマシン上にホームディレクトリを持っているボブが アリスの作業を手伝いたいとします。

ボブは次のようにして自分の作業用エリアを作成します。

bob$ git clone /home/alice/project myrepo

これによりアリスのリポジトリの複製を含んだ "myrepo" という 新規ディレクトリが作成されます。 この複製は元のプロジェクトと対等な立場であり、元のプロジェクトの 履歴のコピーを持っています。

次に、ボブはいくつか変更をしてコミットします:

(edit files)
bob$ git commit -a
(repeat as necessary)

準備ができたら、彼は /home/bob/myrepo にあるリポジトリから変更を 取得(pull)するようにアリスに伝えます。 彼女は以下のようにして取得します:

alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master

これはボブの "master" ブランチで行なわれた変更をアリスの現在のブランチにマージします。 アリスが自身の変更もしている場合は、彼女は手動で全てのコンフリクト(競合)を 解消する必要があります。

この結果からもわかるとおり、"pull" コマンドは次の2つの操作を実行します: (1) リモートブランチから変更を取得。(2) それらを現在のブランチにマージ。

ここで留意すべき事は、通常アリスはこの"pull"を開始するに先立って彼女のローカ ルな変更をコミットしておきたいだろうということです。(そうしておかないと)互 いの履歴が分岐しているため、ボブの作業がアリスが行ったものと競合する場合、 アリスは競合を解消するために彼女のワーキングツリーとインデックスを使用するこ とになりますが、 すでに存在するローカルな変更が競合の解決プロセスの妨げとなっ てしまいます。 (git はfetchは行ってくれますがマージを拒否するでしょう --- そうなった場合、アリスは彼女の ローカルな変更を何らかの方法で取り消してから 改めてpullしなければなりません)。

アリスはまず最初にマージを行う前にボブの作業を"fetch"コマンドを使用して覗き 見るすることができます。これによりアリスは特別なシンボル"FETCH_HEAD"を使用し てボブの作業が pullするに値するかどうかを検査することができます。 これは以下のように行います。

alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD

この操作はたとえアリスがコミットしていないローカルな変更を 行っていても安全です。 範囲表記HEAD..FETCH_HEADはFETCH_HEADから到達可能だが、 HEADからは到達可能で はないもの全てを表すという意味です。 アリスはすでに現在の状態(HEAD)に至まで の全てを知っています、 そしてこのコマンドによって彼女にとって未知な、 ボブが 彼の状態(FETCH_HEAD)に至るまでに行った作業を 検討できます。

もしアリスがフォーク後にボブが行った作業を ビジュアル化したいならば次のコマンドを実行します。

$ gitk HEAD..FETCH_HEAD

これは先ほど'git log'で見た2つのドットで表した範囲表記を使用します。

アリスは分岐以降に彼ら二人が行った作業を見たいかもしれません。 彼女は2つドットのかわりに3つのドットを使用できます。

$ gitk HEAD...FETCH_HEAD

これはどちらか片方から到達可能だが、両方からは 到達可能ではないコミットすべてを表すという意味です。

ここで留意すべき事は、これらの範囲表記はgitkと"git log" 両方で使用可能であるということです。

ボブの作業を検査した後、急を要するものがなければ、 アリスはボブからpullをせ ずに自分の作業を続行することができます。 もしボブの履歴にすぐ必要となるもの があれば、アリスはまず最初に処理中の作業を"stash"し、 "pull"を行った後、その 履歴の先頭に処理中の作業を"stash"から戻す、ということもできます。

(1) と (2) の操作を同時に行なわず、別々に実行したい場合もあるかもしれません。 (具体的には、リモートブランチで行なわれた変更を別のブランチ名で自身のリポジトリ上にコピーし、 その後に、変更点を確認してから現在のブランチにマージしたい場合です) remote リポジトリの略称を登録することで、この作業をより簡単に行うことができます:

alice$ git remote add bob /home/bob/myrepo

この結果、git-fetch コマンドを使用して、それら変更を彼女の自身の ブランチにマージすることなしに、(1) の操作を単独で実行できるようになります。 次のようにです:

alice$ git fetch bob

pull を使用した時と異なり、、git-remote によって設定したリモートリポジトリの略記 を用いてアリスがボブから変更を取得した場合、 取得した変更はリモート追跡用ブランチに格納されます。 上記例の場合、bob/master ブランチです。 その為、この後に

alice$ git log -p master..bob/master

を実行すると、ボブがアリスの master ブランチから分岐した以降のボブの変更 全てが表示されます。

それら変更を確認した後に、アリスは彼女の master ブランチに変更をマージ することができます。次のようにします:

alice$ git merge bob/master

この merge彼女自身のリモート追跡ブランチから取得(pull)する ことによって 行うこともできます。次のようにします:

alice$ git pull . remotes/bob/master

git pull は常に現在のブランチにマージすることに注意してください。 これは他に何かコマンドラインで与えられていても関係ありません。

その後、ボブは次のようにしてアリスの最新の変更状態で彼のリポジトリを 更新することができます。

bob$ git pull

彼がアリスのリポジトリパスを与える必要がないことに注意してください; これはボブがアリスのリポジトリを複製したときに、git は彼女の リポジトリの位置をリポジトリ構成内に格納しているためです。 そして、そのリポジトリ位置が pull した時に使用されます。

bob$ git config --get remote.origin.url
/home/alice/project

(git-clone により作成された完全な構成は git config -l を使用する と確認できます。また、git-config(1) の man ページにて 各オプションの意味が説明されています)

また、gitは "origin/master" という名前でアリスの master ブランチの 初期コピーを保持します:

bob$ git branch -r
  origin/master

ボブが後に異なるホストで作業することを決めたなら、彼は、 ssh プロトコルを使用して clone と pull をすることができます:

bob$ git clone alice.org:/home/alice/project myrepo

代わりに、gitが持っているネイティブなプロトコルか、rsync, http を 使用することもできます; 詳細は git-pull(1) を参照してください。

git はまた、CVS ライクなモードで使用することもできます。 つまり、中央リポジトリを持ち、様々なユーザが変更を push するような使用法です。 それらの詳細は git-push(1)gitcvs-migration(7) を 参照してください。

履歴の探索

git の履歴は一連の相関的なコミットにより表されています。 我々は既に git-log コマンドがそれらのコミットをリスト表示するのを 見ました。 各 git log エントリの最初の行が、そのコミットに対する名前を示していることに 注意してください。

$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <[email protected]>
Date:   Tue May 16 17:18:22 2006 -0700

    merge-base: Clarify the comments on post processing.

この名前を'git-show'コマンドで使用すると、そのコミットに関する詳細を見ることができます。

$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

しかし、それ以外にもコミットを参照する方法があります。 git log が示すコミットの名前全てではなく、 そのコミットを一意に特定できるだけの十分な長さをもった先頭の数文字を 用いる方法です。

$ git show c82a22c39c   # コミット名の最初の数文字で
                        # 大抵は十分です
$ git show HEAD         # 現在のブランチの先端(tip)
$ git show experimental # ブランチ "experimental" の先端(tip)

全てのコミットは常に1つの "parent"(親) のコミットを持ち、 それはプロジェクトの1つ前の状態を指し示します:

$ git show HEAD^  # HEAD の親を表示
$ git show HEAD^^ # HEAD の祖父を表示
$ git show HEAD~4 # HEAD の4つ前を表示

マージコミットは1つ以上の親を持つ場合があることに注意してください:

$ git show HEAD^1 # HEAD の1つ目の親を表示(HEADと同じ)
$ git show HEAD^2 # HEAD の2つ目の親を表示

また、コミットの名前をつけることもできます;次のコマンド

$ git tag v2.5 1b2e1d63ff

を実行すると、"v2.5" という名前で 1b2e1d63ff を参照できるようになります。 この名前を(例えば、リリースバージョンを特定する為に)他の人々と共有するには、 "tag" オブジェクトを作成し、それに署名をつけるべきです。; 詳細は git-tag(1) を参照してください。

コミットを知る必要のあるどんな git コマンドも、 この名前を用いることができます。 例えば以下のとおりです:

$ git diff v2.5 HEAD     # 現在の HEAD を v2.5 と比較
$ git branch stable v2.5 # v2.5の位置に "stable" という名前の新しい
                         # ブランチを作成
$ git reset --hard HEAD^ # 現在のブランチと作業ディレクトリをリセットし、
                         # HEAD^ の状態にします

上記の最後のコマンドに注意してください: 作業ディレクトリ内の変更を失うことに加えて、このブランチから 全ての保留中のコミットを削除してしまうでしょう。 もしこのブランチがそれらコミットを含む唯一のブランチであった場合、 それらコミットは削除されます。 また、他の開発者がそこから pull するような公的に目に見えるブランチでは git-reset は使用しないでください。もしそうすると、他の開発者に 履歴をきれいにするために、不必要なマージを強制させることになります。 あなたが push した変更を元に戻す必要があるなら、git-revert を その代わりに使用してください。

git-grep コマンドは当該プロジェクトの任意のバージョン内の文字列を検索することができます。 例えば、

$ git grep "hello" v2.5

は v2.5 内の "hello" を全文検索します。

コミット名を省いた場合、git-grep は現在のディレクトリ内で履歴管理 対象下にある全てのファイルを検索します。 従って、次のコマンド

$ git grep "hello"

は、git により追跡されているファイルに対して検索する手っとり早い方法です。

git コマンドはまた、コミットの集合を扱うこともできます。 その方法は何通りもの方法があります。 以下は、git-log における使用例です。

$ git log v2.5..v2.6            # v2.5 から 2.6 までのコミット
$ git log v2.5..                # v2.5 以降のコミット
$ git log --since="2 weeks ago" # 最近2週間のコミット
$ git log v2.5.. Makefile       # v2.5 以降に Makefile を
                                # 変更しているコミット

git log にコミットの "範囲" を指定することもできます。 その際、範囲指定の1つ目は必ずしも2つ目の祖先である必要はありません; 例えば、ブランチ "stable-release" と "master" の先端(tip)は、 ある時点の共通のコミットから枝分かれしている場合、次のコマンド

$ git log stable..experimental

は、ブランチ experimental にあって、ブランチ stable に存在しないコミットとリストを 表示します。一方、次のコマンド

$ git log experimental..stable

は、ブランチ stable にあって、ブランチ experimental に存在しない コミットのリストを表示します。

git-log コマンドには弱点があります: それはコミットのリスト表示に関するものです。 履歴が枝分かれし両者がマージされた開発ラインを持つ場合、git-log の コミットの表示順序には意味がありません。

複数の貢献者を持つプロジェクト(例えば Linux カーネルや git自身)は、 頻繁にマージが行われます。gitk はそれら履歴をビジュアルに表示するので 大変重宝します。 例えば、次のコマンド

$ gitk --since="2 weeks ago" drivers/

を行うことで、最近2週間に "drivers" ディレクトリを修正したコミットを 閲覧することができます。 (注意: gitk のフォントはコントロールキーを押さえながら "-" か "+" を押すことで調整できます。)

最後に、オプションとしてファイル名を引数に取る大抵のコマンドが コミットにファイル名を付けられる点を説明します。 あるファイルの特定のバージョンを指し示すには次のようにします:

$ git diff v2.5:Makefile HEAD:Makefile.in

git-show コマンドでも、次のようにファイルを指定できます:

$ git show v2.5:Makefile

次のステップ

このチュートリアルは、あなたのプロジェクトで基本的な分散リビジョン管理を 行うには十分なはずです。 しかし、git の奥深さと能力を十分に理解するには、git の ベースになっている2つのシンプルなアイデアを理解する必要があります。:

チュートリアルのパート2では、 オブジェクトデータベース、索引ファイル、そして git を最大限利用するため必要となる残りの部分について説明します。 gittutorial-2(7)を参照して下さい.

今すぐ続きを学習したくない人は、この時点から他に以下のような 脱線をしてみるのも面白いでしょう。

参考

gittutorial-2(7), gitcvs-migration(7), gitcore-tutorial(7), gitglossary(7), git-help(1), Everyday git, The Git User's Manual

GIT

git(1) スイートの一部