htmlcss git の基本的な使い方に関するメモ

2015年3月8日

Windows 環境での git(バージョン管理システム/VCS)の使い方等に関する個人的なメモ(自分の学習のためのまとめ)。

公式サイト:http://git-scm.com/

参考にさせていただいたサイト

目次

git の構造(メモ)

Git リポジトリ
作業ディレクトリ(ワーキングツリー)
作業(直接編集)するファイルが入っている
.git ディレクトリ
リポジトリの本体
リポジトリはコミットの集合で、各コミットはプロジェクトにおいて過去に存在したワーキングツリーのアーカイブ。またリポジトリは、現在のワーキングツリーがどのブランチまたはコミットから由来しているのかを特定する、HEAD というものを定義する。さらに、ブランチやタグという、コミットを名前で把握するためのものが含まれている。

git_06

ワーキングツリー
関連するリポジトリを持った、ファイルシステム上のあるディレクトリのこ(.git という名前のサブディレクトリが存在する)。ワーキングツリーには全てのファイルとサブディレクトリが含まれている。
コミット
ある時点でのワーキングツリーのスナップショット。そのコミットをする時点の HEAD の状態が、そのコミットの親になる。
インデックス(ステージングエリア)
Git はワーキングツリーからリポジトリへ変更を直接コミットせずに、変更はまずインデックス (index) と呼ばれる場所へ登録される。
index は、次のコミットのためのステージングエリア
ブランチ
コミットの別名のようなもの(コミットを指すポインタ)。リポジトリの履歴を定義するコミットの系統図で、「開発における枝分かれ」を表現する典型的概念
.git の中身
  • Git オブジェクト
  • リファレンス
  • インデックス
  • ログ
  • 設定

git_07

Git オブジェクト
  • tree:ディレクトリ
  • blob:ファイル
  • commit:コミット
  • tag:タグ
Git オブジェクトは、ID (オブジェクト名) で区別でき、ID は 40 文字の 16 進数
ID を見ても、オブジェクトの種類は区別がつかない。4種類のオブジェクトがランダムに .git/objects ディレクトリに入っている
リファレンス
  • 特定の commit オブジェクト (または tag オブジェクト) を指し示すブックマークのようなもの。
  • リファレンスが指し示す commit オブジェクトからたどり、他のオブジェクトを引き出すことが可能になっている。
  • リファレンスには Git オブジェクトの ID がテキストで書いてある。
リファレンスのリファレンス
他のリファレンスを指し示すリファレンス。
.git/HEAD リファレンスには、「ref: refs/heads/master」 のように書いてあり、この形式のリファレンスは、 commit オブジェクトを指し示すのではなく、別のリファレンス .git/refs/heads/master を指し示している。
HEAD リファレンスは git checkout コマンドで書き換わる。
HEAD
特別なリファレンスファイル。現在チェックアウトしているブランチを示す。
tree と blob オブジェクト
Git に追加したディレクトリやファイルは、tree オブジェクトや blob オブジェクトとして、オブジェクトデータベースに保存される。tree はディレクトリ、blob はファイルに相当する。
blob オブジェクト:ファイルの中身がそのまま書かれている。
tree オブジェクト:あるディレクトリに含まれるファイル名・サブディレクトリ名と、そのオブジェクト ID が一覧で書かれている。
commit オブジェクト
「いつ、誰が、どのようにファイルツリーを変えたか」を管理するもので以下のような情報が書かれている。
  • tree : 1つの tree オブジェクトの ID
  • parent : 0個以上の親 commit オブジェクトの ID
  • author, committer :変更・コミットしたユーザの名前、メールアドレス、変更日時
  • コミットメッセージ
Git における一般的な流れ
リポジトリを作成した後、作業はワーキングツリーで行われる。作業が一段落したら逐次変更をインデックスに追加する。コミットしたい全てのものがインデックスに追加されたら、その内容をリポジトリに記録(コミット)する。

以下のサイトを参考にさせていただきました。
Git の仕組み/こせきの技術日記
【翻訳】Gitをボトムアップから理解する

git のインストール(Windows)

以下のサイト(Git for Windows)からダウンロードして、インストール

http://msysgit.github.io/

インストールされた Git Bash を使用

git_01

git_02

git の設定

git config ツールで設定する。

個人の識別情報の設定:名前とメールアドレスを設定(必須)

git config --global user.name "James Brown"
git config --global user.email "james@brown.com"

メッセージを色分けして表示する設定(オプション)

git config --global color.ui true

git config ツールで設定された値は以下のファイルに保存される。

/etc/gitconfig ファイル
システム上の全てのユーザーと全てのリポジトリに対する設定値を保持。
–system オプションを git config に指定すると、このファイルに読み書きを行なう。
Windows の場合は C:\Program Files (x86)\Git\etc
~/.gitconfig ファイル
特定のユーザーに対する設定値を保持。
–global オプションを指定すると、このファイルに読み書きを行なう。
Windows の場合は C:\Users\$USER
.git/config
特定の単一リポジトリに対する設定値を保持
それぞれの Git ディレクトリ内の .git/config

設定の確認 / 設定の一覧表示

git config -l
#または
git config --list

参考元:最初のGitの構成/Pro Git

ヘルプの表示

$ git help <verb>
#または
$ git <verb> --help

<verb> はサブコマンド。

git config のヘルプの表示

git config --help

全ての git コマンドの表示。

git --help -a
usage: git [--version] [--help] [-C <path>] [-c name=value]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

available git commands in 'C:\Program Files (x86)\Git/libexec/git-core'

  add                 get-tar-commit-id   receive-pack
  add--interactive    grep                reflog
  am                  gui                 relink
  annotate            gui--askpass        remote
  apply               gui--askyesno       remote-ext
  ・・・省略・・・

参考元:ヘルプを見る/Pro Git

Git リポジトリの取得

リポジトリ
ファイルやディレクトリの状態を記録する場所。保存された状態は、内容の変更履歴として格納されている。

Git プロジェクトを取得するには、既存のディレクトリでリポジトリの初期化をするか、既存の Git リポジトリを別のサーバーからクローンする方法の2通りがある。

既存のディレクトリでのリポジトリの初期化

プロジェクトを git で使用(管理)するには、そのプロジェクトのディレクトリに移動して「git init」で初期化(空のリポジトリの作成、または既存のリポジトリの初期化)する。

git init

$ git init
Initialized empty Git repository in C:/xampp/htdocs/git_test/.git/

上記を実行すると .git という名前の新しいサブディレクトリ(隠しフォルダー)が作られ、リポジトリに必要なすべてのファイル (Git リポジトリのスケルトン) がその中に格納される。この時点では、まだプロジェクト内のファイルは一切管理対象になっていない。

既存のリポジトリのクローン

既存の Git リポジトリのコピーを取得したい場合には、git clone コマンドを使用する。

リポジトリをクローンするには git clone [url] とする。

Ruby の Git ライブラリである Grit をクローンする例。

$ git clone git://github.com/schacon/grit.git

これは、まず grit というディレクトリを作成してその中で .git ディレクトリを初期化し、リポジトリのすべてのデータを引き出し、そして最新バージョンの作業コピーをチェックアウトする。新しくできた grit ディレクトリには、プロジェクトのファイルが入っている。

grit ではない別の名前のディレクトリにクローンしたいのなら、コマンドラインオプションでディレクトリ名を指定。

$ git clone git://github.com/schacon/grit.git mygrit

このコマンドは先ほどと同じ処理を行うが、ディレクトリ名は mygrit になる。

「ディレクトリでのリポジトリの初期化」または「既存のリポジトリのクローン」により、Git リポジトリを準備して、そのプロジェクト内のファイルの作業コピーを取得することができる。

既存のディレクトリでリポジトリの初期化の例

「MyProject01」という空のディレクトリ(C:\xampp\htdocs\MyProject01)を作成した場合の例。

Git Bash を起動して、「MyProject01」ディレクトリへ移動。
git init を実行

$ cd ../../xampp/htdocs/MyProject01

$ git init
Initialized empty Git repository in c:/xampp/htdocs/MyProject01/.git/

index.html というファイルを「MyProject01」ディレクトリに作成し、その後ファイルの状態を「git status」で確認すると以下のように表示される。

$ git status
On branch master
Initial commit
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html
nothing added to commit but untracked files present (use "git add" to track)

今度は「MyProject02」というディレクトリ(C:\xampp\htdocs\MyProject02)を作成し、その中にindex.html というファイルを作成し、 git init を実行後、「git status」で確認すると以下のように表示される。

$ cd ../MyProject02

$ git init
Initialized empty Git repository in c:/xampp/htdocs/MyProject02/.git/

$ git status
On branch master
Initial commit
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html
nothing added to commit but untracked files present (use "git add" to track)

この時点ではいずれの場合も、index.html は「Untracked files」として表示されている。

これは、Git が「前回のスナップショット (コミット) にはこのファイルが存在しなかった」とみなしたということで、明示的に指示しない限り、Git はコミット時にこのファイルを含めることはない。

参考元:Git リポジトリの取得/Pro Git

変更内容のリポジトリへの記録

次は、そのコピーに対して何らかの変更を行い、適当な時点で変更内容のスナップショットをリポジトリにコミットする。

コミット
ファイルやディレクトリの追加や変更等を、リポジトリに記録する操作。コミットを実行すると、リポジトリ内で、前回コミットした時の状態から現在の状態までの差分を記録したコミット(またはリビジョン)と呼ばれるものが作成される。
Git にコミットすると、Git はコミットオブジェクトを作成して格納する。このオブジェクトには、以下が含まれる。

  • ステージしたスナップショットへのポインタ
  • 作者・メッセージのメタデータ
  • そのコミットの直接の親となるコミットへのポインタ

作業コピー内の各ファイルには 追跡されている(tracked) ものと 追跡されてない(untracked) ものの二通りがある。

  • tracked
  • untracked
追跡されているファイル(tracked)
直近のスナップショットに存在したファイルのこと。
これらのファイルには以下の3つの状態がある。

  • 変更されていない(unmodified)
  • 変更されている(modified)
  • ステージされている(staged)
追跡されていないファイル(untracked)
直近のスナップショットには存在せず、ステージングエリアにも存在しないファイルのことで、前述の3つの状態のどの状態にも属さない。

また、最初にプロジェクトをクローンした時点では、すべてのファイルは「追跡されている」かつ「変更されていない」状態となる。(チェックアウトしただけで何も編集していない状態のため)

  • ファイルを編集すると、Git はそれを「変更された」とみなす。
  • 変更されたファイルを ステージ し、それをコミットする。
  • この繰り返し。

新しいファイルをプロジェクト(ステージング・エリア)に追加

新しいファイルの追跡を開始するには git add コマンドを使用して新しいファイルをプロジェクト(ステージング・エリア)に追加する。

git add index.html

その後、「git status」で確認すると以下のように表示され、ファイルが追跡対象となり、ステージされていることがわかる。

$ git status
On branch master
Initial commit
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   index.html

“Changes to be committed” 欄に表示されているので、ステージされていると判断できる。
ここでコミットを行うと、git add した時点の状態のファイルがスナップショットとして履歴に書き込まれる。

git add コマンド
ファイルあるいはディレクトリのパスを指定。ディレクトリを指定した場合は、そのディレクトリ以下にあるすべてのファイルを再帰的に追加する。

git add コマンドには色々な意味合いがあり、以下のような場合などに使用する。

  • 新しいファイルの追跡開始
  • ファイルのステージング
  • マージ時に衝突が発生したファイルに対する「解決済み」マーク付け

変更したファイルのステージング

すでに追跡対象となっているファイル index.html を変更して status コマンドを実行すると、結果は以下のようになる。

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
        modified:   index.html
no changes added to commit (use "git add" and/or "git commit -a")

index.html ファイルは “Changes not staged for commit” という欄に表示されている。これは、追跡対象のファイルが作業ディレクトリ内で変更されたけれどもまだステージされていないという意味。

ステージするには git add コマンドを実行する。

その後再度 git status を実行すると、結果は以下のようになる。

$ git add index.html

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        modified:   index.html

コミットする前に更にここで、index.html ファイルに変更を加えて、再度 git status を実行すると、結果は以下のようになる。

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
        modified:   index.html

index.html ファイルは“Changes to be committed” 欄と “Changes not staged for commit” 欄の両方に表示されている。

これは、Git は git add コマンドを実行した時点の状態のファイルをステージするということ。

ここでコミットをすると、実際にコミットされるのは git add を実行した時点の index.html であり、git commit した時点の作業ディレクトリにある内容とは違うものになる。

git add した後にファイルを変更した場合に、最新版のファイルをステージしなおすにはもう一度 git add を実行する必要がある。

ワイルドカード

複数のファイルを一度にステージする場合、ワイルドカード(*)が使える。

以下は、全ての html ファイルをステージする例。この場合、クオートで囲む必要がある。

$ git add '*.html'

全てのファイルをステージする例。(ドットのみ)

$ git add .

ファイルの無視

Git に自動的に追加してほしくない場合や「Untracked files: 追跡されていない」と表示されないようにするには、.gitignore というファイルを作成し、無視させたいファイルのパターンを記述する。

(例)git status を実行すると以下のように表示され、ignoreThis.txt というファイルと log というディレクトリを無視したい場合。

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        ignoreThis.txt
        log/
nothing added to commit but untracked files present (use "git add" to track)

vim で .gitignore ファイルを作成

$ vim .gitignore

無視させたいファイルのパターンを記述

.gitignore

#comment コメント
ignoreThis.txt
log/

git status で確認すると、ignoreThis.txt というファイルと log というディレクトリは無視されている。

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore
nothing added to commit but untracked files present (use "git add" to track)

.gitignore ファイルに記述するパターンの規則

  • 空行あるいは # で始まる行は無視される
  • 標準の glob パターンを使用可能
  • ディレクトリを指定するには、パターンの最後にスラッシュ (/) をつける
  • パターンを逆転させるには、最初に感嘆符 (!) をつける
glob パターン
シェルで用いる簡易正規表現のようなもの
  • アスタリスク (*) は、ゼロ個以上の文字にマッチ
  • [abc] は、角括弧内の任意の文字 (この場合は a、b あるいは c) にマッチ
  • 疑問符 (?) は一文字にマッチ
  • ハイフン区切りの文字を角括弧で囲んだ形式 ([0-9]) は、ふたつの文字の間の任意の文字 (この場合は 0 から 9 までの間の文字) にマッチ

ステージされている変更 / されていない変更の確認

変更したけれどもまだステージしていない内容を見るには、引数なしで git diff を実行。このコマンドは、作業ディレクトリの内容とステージングエリアの内容を比較する。

$ git diff
diff --git a/index.html b/index.html
index 8c1daee..134dcf7 100644
--- a/index.html  #変更前
+++ b/index.html  #変更後
@@ -5,6 +5,6 @@
        <title>My Project01</title>
 </head>
 <body>
-<p>my test project</p>  #ステージングエリアの内容
+<p>my test projectX</p>^M  #作業ディレクトリの内容
 </body>
 </html>

次のコミットに含めるステージされた内容を知りたい場合は、git diff –staged(または git diff –cached)を使用。このコマンドは、ステージされている変更と直近(前回)のコミットの内容を比較する。

$ git diff --staged
diff --git a/index.html b/index.html
index e1ff4aa..8c1daee 100644
--- a/index.html  #変更前
+++ b/index.html  #変更後
@@ -5,6 +5,6 @@
        <title>My Project01</title>
 </head>
 <body>
-<p>test</p>  #直近(前回)のコミットの内容
+<p>my test project</p>^M  #ステージされている変更
 </body>
 </html>

変更のコミット(リポジトリに保存)

ステージングエリアの準備ができたら、変更内容をコミットすることができる。

コミットの対象となるのはステージされたものだけ、つまり追加したり変更したりしただけでまだ git add を実行していないファイルはコミットされず、そういったファイルは、変更されたままの状態でディスク上に残る。

コミットするには git commit を実行する。

$ git commit

git commit を実行すると、デフォルトのエディタ(vim)が立ち上がる。
(git config –global core.editor コマンドで好みのエディタを指定することも可能)

エディタには次のようなテキストが表示される (これは Vim の画面の例)。

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#       modified:   index.html
#
~
~
~
<\xampp\htdocs\MyProject-1\.git\COMMIT_EDITMSG [unix] (18:27 14/03/2015)1,0-1 All

「i」キーを押して、インサートモードにして、変更履歴等の情報(メッセージ)を入力後、「Esc」キーを押してコマンドモードに戻り、「:wq」で保存してエディタを終了。(メッセージを入力せず、「:q」で終了するとコミットは行われない。)

何を変更したのかをより明確に知りたい場合は、git commit に -v オプションを指定。そうすると、diff の内容がエディタに表示されるので何を行ったのかが正確にわかる。エディタを終了させると、Git はそのメッセージつきのコミットを作成する(コメントおよび diff は削除される)。

git_04

または、コミットメッセージをインラインで記述することも可能。その場合は、commit コマンドの後で -m フラグに続けてメッセージを記述する。

$ git commit -m "commit message test"
[master 8744870] commit message test
 1 file changed, 1 insertion(+), 1 deletion(-)

git commit を実行すると、「どのブランチにコミットしたのか (master)」「そのコミットの SHA-1 チェックサム (8744870)」「変更されたファイルの数」「そのコミットで追加されたり削除されたりした行数」といった情報が表示される。

ステージングエリアの省略

ステージングエリアを省略したい場合には、git commit コマンドに -a オプションを指定すると、追跡対象となっているファイルを自動的にステージしてからコミットを行うので、git add を省略できる。

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
        modified:   index.html
no changes added to commit (use "git add" and/or "git commit -a")

$ git commit -a -m "added new line"
[master 68d7d05] added new line
 1 file changed, 1 insertion(+)

ファイルの削除

プロジェクトに追加されているファイルを Git から削除するには、追跡対象から外し(ステージングエリアから削除し)、そしてコミットする。git rm コマンドは、この作業を行い、そして作業ディレクトリからファイルを削除する。

単に作業ディレクトリからファイルを削除しただけの場合は、git status の出力の中では “Changes not staged for commit” (ステージされていない) 欄に表示される。

$ rm test01.txt  #単に作業ディレクトリからファイルを削除

$ git status  #“Changes not staged for commit”  欄に表示される
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
        deleted:    test01.txt
no changes added to commit (use "git add" and/or "git commit -a")

git rm コマンドでファイルを追跡対象から外す。(ステージングエリアから削除)。
次にコミットするときにファイルが削除され、追跡対象外となる。

$ git rm test01.txt
rm 'test01.txt'

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        deleted:    test01.txt

$ git commit
[master 3e99c63] remove test01.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 test01.txt

$ git status
On branch master
nothing to commit, working directory clean

変更したファイルをすでにステージしている場合は、-f オプションで強制的に削除しなければならない。

ハードディスク上にはファイルを残しておきたいけれど、もう Git では追跡させたくないというような場合は –cached オプションを使用する。

$ git rm --cached test01.txt
rm 'test01.txt'

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        deleted:    test01.txt
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test01.txt

$ git commit
[master 3031417] removed
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 test01.txt

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test01.txt
nothing added to commit but untracked files present (use "git add" to track)

ファイルの移動

Git には mv コマンドがあり、Git の中でファイル名を変更したい場合は次のようなコマンドを実行する。

$ git mv file_from file_to

test01.txt を sample01.txt という名前に変更する例。(git status は確認のために実行)

$ git mv test01.txt sample01.txt

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        renamed:    test01.txt -> sample01.txt

$ git commit -m "change name"
[master b3cb6ba] change name
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename test01.txt => sample01.txt (100%)

$ git status
On branch master
nothing to commit, working directory clean

git mv test01.txt sample01.txt は実際には以下を実行したのと同じこと。

$ mv test01.txt sample01.txt
$ git rm test01.txt
$ git add sample01.txt

参考元:変更内容のリポジトリへの記録/Pro Git

履歴の表示

コミット履歴を表示させるには git log コマンドを実行する。

$ git log
commit c3fe70a5097a09f4f4564de1dd48c60c521ab08f #SHA-1 チェックサム(IDのようなもの)
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 8 17:48:46 2015 -0400

    My initial test commit 2 #コミットの際に入力したメッセージ

デフォルトで引数を何も指定しなければ、そのリポジトリでのコミットを新しい順に表示する。

このコマンドは各コミットについて SHA-1 チェックサム、作者の名前とメールアドレス、コミット日時、コミットメッセージを一覧表示する。

履歴が増えてくるなどして見ずらくなった場合に1行で表示せるには「–oneline」オプションを指定することができる。

$ git log --oneline
eee4a99 add more lines
d7a8a6d change text and add line
e4b5e69 add some text
b3cb6ba change name
3031417 removed
3e99c63 remove test01.txt
09dc320 deleted
c9ce494 added
f01dc07 test
68d7d05 added new line
8744870 commit message test

各コミットの diff を表示 -p

-p オプションを指定すると、各コミットの diff を表示する。また -3 は、直近の 3 エントリだけを出力する。

$ git log -p -3
commit e4b5e695ebc988a5ed1b03a3bb10adf2803c22f9
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 11:59:36 2015 -0400

    add some text

diff --git a/sample01.txt b/sample01.txt
index e69de29..2be1882 100644
--- a/sample01.txt
+++ b/sample01.txt
@@ -0,0 +1 @@
+add some text
\ No newline at end of file

commit b3cb6bac523485c8ed30cf89fbdf05112f6ab485
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 11:23:29 2015 -0400

    change name

diff --git a/sample01.txt b/sample01.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test01.txt b/test01.txt
deleted file mode 100644
index e69de29..0000000

commit 5bd80b7aadad643e49ae2956c30d90d90256cf21
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 10:55:24 2015 -0400

    test commit

diff --git a/test01.txt b/test01.txt
new file mode 100644
index 0000000..e69de29
単語単位でレビュー

git log -p コマンドのオプション –word-diff を使えば、通常の行単位diffではなく、単語単位のdiffを表示させることが可能。

追加された単語は {+ +} で、削除された単語は [- -] で囲まれて表示される。

$ git log -p --word-diff -2
commit eee4a998718230270878e81789d60b8d2929eb6c
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 12:15:08 2015 -0400

    add more lines

diff --git a/sample01.txt b/sample01.txt
index 781846a..934ae51 100644
--- a/sample01.txt
+++ b/sample01.txt
@@ -1,2 +1,4 @@
add some words
add new line
{+more lines^M+}
{+more words+}

commit d7a8a6dd1e1907cbcbaf99a5b4f8b28ccb36c0f5
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 12:11:09 2015 -0400

    change text and add line

diff --git a/sample01.txt b/sample01.txt
index 2be1882..781846a 100644
--- a/sample01.txt
+++ b/sample01.txt
@@ -1 +1,2 @@
add some [-text-]{+words^M+}
{+add new line+}

統計情報の表示

各コミットの変更のあったファイルの統計情報を見たい場合は –stat オプションを指定する。

$ git log --stat -3
commit eee4a998718230270878e81789d60b8d2929eb6c
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 12:15:08 2015 -0400

    add more lines

 sample01.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

commit d7a8a6dd1e1907cbcbaf99a5b4f8b28ccb36c0f5
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 12:11:09 2015 -0400

    change text and add line

 sample01.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

commit e4b5e695ebc988a5ed1b03a3bb10adf2803c22f9
Author: Web Design Leaves <xxxx@webdesignleaves.com>
Date:   Sun Mar 15 11:59:36 2015 -0400

    add some text

 sample01.txt | 1 +
 1 file changed, 1 insertion(+)

ログ出力の制限

コミットの一部だけを表示する以下のようなオプションがある。

ログ出力制限オプションの例
オプション 説明
-(n) 直近の n 件のコミットのみを表示
– -since, – -after 指定した日付/時刻以降のCommitDateのコミットのみに制限
– -until, – -before 指定した日付/時刻以前のCommitDateのコミットのみに制限する

過去二週間のコミットの一覧を取得

$ git log --since=2.weeks

2015/3/15 12:00 ~ 2015/3/15 13:00 のコミットの一覧を取得

$ git log --after="2015-03-15 12:00:00" --before="2015-03-15 13:00:00"

この他にもいろいろなオプションがある。

GUI による履歴の可視化

グラフィカルなツールでコミットの履歴を見たい場合は、Tcl/Tk のプログラムである gitk を使える。

プロジェクトのコマンドラインで gitk と打ち込むと、以下のような画面が表示される。

ウィンドウの上半分に、コミットの履歴が表示され、ウィンドウの下半分には diff ビューアがあり、任意のコミットをクリックしてその変更内容を確認することができる。

git_05

参考元:コミット履歴の閲覧/Pro Git

作業のやり直し

直近のコミットの変更

「直前のコミットで、追加すべきファイルを忘れてしまいファイルを後から追加する」場合や「直前のコミットのコメントを修正する」場合は、–amend オプションをつけてもう一度コミットする。

$ git commit --amend

このコマンドは、ステージングエリアの内容をコミットに使用。直近のコミット以降に何も変更をしていない場合、スナップショットの内容は同じでありコミットメッセージを変更することになる。

コミットメッセージのエディタが立ち上がり、既に前回のコミット時のメッセージが書き込まれた状態になっているので、編集する。

また、コミットした後、何かのファイルをステージするのを忘れていたのに気づいた場合は次のようにする。

$ git commit -m 'コミットメッセージ'
$ git add ステージするのを忘れていたファイル
$ git commit --amend

2番目のコミットが、最初のコミットの結果を上書きする。

ステージしたファイルの取り消し

2つのファイルを変更し、それぞれを別のコミットとするつもりだったが git add . と打ち込んでしまったため両方のファイルステージされてしまった場合、いずれかのファイルのステージを解除したい場合、git status コマンドを実行してみる。

$ git add .

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        modified:   index.html
        modified:   sample01.txt

「use “git reset HEAD …” to unstage」というメッセージが表示されているのがわかる。

index.html を解除するには以下のようにする。

$ git reset HEAD index.html
Unstaged changes after reset:
M       index.html

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

        modified:   sample01.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   index.html

ファイルへの変更の取り消し

ファイルに加えた変更を取り消す (直近のコミット時点の状態に戻す) には、git checkout — コマンドを利用できる。

git status の出力結果で、ステージされていないファイル一覧の部分に「use “git checkout — …” to discard changes in working directory」というメッセージが表示されているのがわかる。

但し、これは危険なコマンドでファイルに加えた変更はすべて消えてしまうので、そのファイルが不要であることが確実な場合のみ、このコマンドを使用するようにする。

$ git checkout -- index.html

参考元:作業のやり直し/Pro Git

タグ

タグ機能を使うと、重要なポイントに印をつけることができる。通常この機能は (v 1.0 など) リリースポイントとして使われることが多い。

タグの一覧表示

既存のタグの一覧を表示するには、単に git tag と打つだけ。
(タグをアルファベット順に表示)

$ git tag

パターンを指定してタグを検索することも可能。例えば、 1.4.1 系のタグのみを見たい場合は、以下のようにする。

$ git tag -l 'v1.4.1.*'
v1.4.1.1
v1.4.1.2

タグの作成

Git のタグには、軽量 (lightweight) 版と注釈付き (annotated) 版の二通りがある。軽量版のタグは、変更のないブランチのようなものです。特定のコミットに対する単なるポインタでしかありません。しかし注釈付きのタグは、Git データベース内に完全なオブジェクトとして格納されます。チェックサムが付き、タグを作成した人の名前・メールアドレス・作成日時・タグ付け時のメッセージなども含まれます。また、署名をつけて GNU Privacy Guard (GPG) で検証することもできます。一般的には、これらの情報を含められる注釈付きのタグを使うことをおすすめします。しかし、一時的に使うだけのタグである場合や何らかの理由で情報を含めたくない場合は、軽量版のタグも使用可能です。

軽量版のタグ(lightweight)
特定のコミットに対する単なるポインタ
注釈付きのタグ (annotated)
Git データベース内に完全なオブジェクトとして格納されて、チェックサムが付き、タグを作成した人の名前・メールアドレス・作成日時・タグ付け時のメッセージなども含まれる。また、署名をつけて GNU Privacy Guard (GPG) で検証することもでる。
注釈付きのタグの作成

簡単な方法は、tag コマンドの実行時に -a を指定する。

-m で、タグ付け時のメッセージを指定。注釈付きタグの作成時に -m を省略すると、エディタが立ち上がるのでそこでメッセージをする。

$ git tag -a v0.1 -m "my version 0.1"

タグのデータとそれに関連づけられたコミットを見るには git show コマンドを使用。

$ git show v0.1
tag v0.1
Tagger: User name <user_email_address>
Date:   Wed Mar 18 18:46:25 2015 -0400

my version 0.1

commit ffc82242c0cceef2538734747de63347f31b9f2c
Author: User name <user_email_address>
Date:   Wed Mar 18 18:31:26 2015 -0400

    add more words

diff --git a/sample01.txt b/sample01.txt
index 934ae51..d87ed50 100644
--- a/sample01.txt
+++ b/sample01.txt
@@ -2,3 +2,4 @@ add some words
 add new line
 more lines
 more words
+another new line addes
\ No newline at end of file

後からのタグ付け

過去にさかのぼってコミットにタグ付けすることも可能。コミットの履歴が次のようなものであった場合、特定のコミットにタグをつけるには、そのコミットのチェックサム (あるいはその一部) をコマンドの最後に指定する。

$ git log --pretty=oneline
22c0c0115f0cb3d6d89831c3e0bcf0ab86502bc0 add h2 tag
34d0ee9bd4ed961f2c081e8be9e22419fcdf9a7c delete some texit and add H1
ffc82242c0cceef2538734747de63347f31b9f2c add more words
d80a5041cbfe9c110df7a62e15f388f73754c12d add more lines
d7a8a6dd1e1907cbcbaf99a5b4f8b28ccb36c0f5 change text and add line
e4b5e695ebc988a5ed1b03a3bb10adf2803c22f9 add some text
b3cb6bac523485c8ed30cf89fbdf05112f6ab485 change name
5bd80b7aadad643e49ae2956c30d90d90256cf21 test commit
3e99c63cf3aee5f8d62efeb4e9016d45f5031deb remove test01.txt
09dc3201ad4a1763ca5e501e5a5d2456a7698675 deleted
(END)

上記の一番最後のコミットにタグをつける例

$ git tag -a v0.01 -m "my version 0.01" 09dc3201

参考元:タグ/Pro Git

ブランチ機能

ブランチ
履歴の流れを分岐して記録していくためのもの。分岐したブランチは他のブランチの影響を受けないため、同じリポジトリ中で複数の変更を同時に進めていくことが可能。
また、分岐したブランチは他のブランチとマージすることで、一つのブランチにまとめ直すことができる。
master ブランチ
リポジトリに最初のコミットを行うと、Git は masterという名前のブランチを作成する。以後のコミットはブランチを切り替えるまで master ブランチに追加されていく。

git commit を実行すると、

  • プロジェクト内全ディレクトリのチェックサムが計算され、tree オブジェクトとして Git リポジトリに格納される。
  • 続いて、メタデータ及び tree オブジェクトへのポインタを含むコミットオブジェクトが作成される。
  • これにより、必要に応じてこのスナップショットを再作成できるようになる。

この時点で、Git リポジトリには以下のオブジェクトが作成されている。

  • ファイルそれぞれの中身をあらわす blob オブジェクト
  • ディレクトリの中身の一覧とどのファイルがどの blob に対応するかをあらわすツリーオブジェクト
  • そのルートツリーおよびすべてのメタデータへのポインタを含むコミットオブジェクト

なんらかの変更を終えて再びコミットすると、次のコミットには直近のコミットへのポインタが格納される。

  • Git におけるブランチとは、単にこれらコミットを指すポインタに過ぎない。
  • Git のデフォルトのブランチ名は master 。
  • 最初にコミットした時点で、直近のコミットを指す master ブランチが作られる。
  • その後コミットを繰り返すたびに、このポインタは自動的に進んでいく。

git_08

ブランチの作成

新しいブランチを作成すると、単に新たな移動先を指す新しいポインタが作られる。

新しい test ブランチを作る例。

$ git branch test

これで、新しいポインタが作られるが、現時点ではふたつのポインタ(master, test)は同じ位置を指している。

git_09

Git は、今どのブランチで作業しているのか知るために、 HEAD と呼ばれる特別なポインタを利用する。つまり HEAD は現在作業しているローカルブランチへのポインタになる。

上記の場合、git branch コマンドは新たにブランチを作成するだけなので、まだ master ブランチにいる。(git branch コマンドはそのブランチに切り替えるわけではない)

git_10

ブランチの切り替え

ブランチを切り替えるには git checkout コマンドを実行する。

$ git checkout test

これで、HEAD は test ブランチを指すようになる。

git_11

ここで別のコミットをする。

$ vim test.html
$ git commit -a -m 'made a change'

HEAD が指すブランチが、コミットによって移動する。

git_12

test ブランチはひとつ進んだが master ブランチは変わらない。git checkout でブランチを切り替えたときの状態のまま。

master ブランチに戻ってみる。

$ git checkout master

git_13

チェックアウトによって HEAD が別のブランチに移動

前述のコマンドは以下の二つの作業をしている。

  • まず HEAD ポインタが指す先を master ブランチに戻す
  • そして作業ディレクトリ内のファイルを master が指すスナップショットの状態に戻す。

この時点以降に行った変更は、これまでのプロジェクトから分岐した状態になり、これは、test ブランチで一時的に行った作業を巻き戻したことになる。

つまり、ここから改めて別の方向に進めるということになる。

ふたたび変更を加えてコミットしてみる。

$ vim test.html
$ git commit -a -m 'made other changes'

git_14

これで、プロジェクトの履歴が二つに分岐した。新たなブランチ(test)を作成してそちらに切り替え、何らかの作業を行い、メインブランチ(master)に戻って別の作業をした状態。

どちらの変更も、ブランチごとに分離している。ブランチを切り替えつつそれぞれの作業を進め、必要に応じてマージすることが可能。

ブランチの基本

数回のコミットをした状態のプロジェクトで作業をしている場合の例

git_15

作業用に新しいブランチ(chg01)を作成する。

ブランチの作成と新しいブランチへの切り替えを同時に行うには、git checkout コマンドに -b スイッチをつけて実行。

$ git checkout -b chg01
Switched to a new branch 'chg01'

これは、次のコマンドを実行したのと同じ。

$ git branch chg01
$ git checkout chg01

git_16

そして何らかの作業をしてコミットすると chg01 ブランチが先に進む。このブランチをチェックアウトしているため、HEAD が chg01 ブランチを指している。

$ git commit -a -m 'changed contents [chg01]'
[chg01 a97d282] changed contents [chg01]
 1 file changed, 1 insertion(+)

git_17

ここで、何らかの問題が発生してそちらの作業を優先しなければならなくなったとする。

この場合、Git を使っていれば、これまでの作業をいったん元に戻してから改めて優先度の高い作業にとりかかるなどという作業も不要。ただ単に、master ブランチに戻るだけ。

但し、注意すべき点がある。

作業ディレクトリやステージングエリアに未コミットの変更が残っている場合、それがもしチェックアウト先のブランチと衝突する内容ならブランチの切り替えはできない。ブランチを切り替える際には、クリーンな状態にしておく必要がある。(これを回避するには、stash およびコミットの amend という処理を行うという方法もある)

この例の場合、変更をコミットし終えているので、master ブランチに戻ることができる。

$ git checkout master
Switched to branch 'master'

git_18

これにより、作業ディレクトリは新しいブランチ(chg01)での作業前の状態に戻る。

これは Git が作業ディレクトリの状態をリセットし、チェックアウトしたブランチが指すコミットの時と同じ状態にするということで、そのブランチにおける直近のコミットと同じ状態にするため、ファイルの追加・削除・変更を自動的に行う。

次に、優先度の高い作業を行うため、優先度の高い作業用に hotfix ブランチを作成し、作業をそこで進めることにする。

$ git checkout -b hotfix
Switched to a new branch 'hotfix'

作業が完了し、変更をコミット。

$ git commit -a -m 'hotfix: fixed layout issue'
[hotfix 73eb219] hotfix: fixed layout issue
 1 file changed, 1 insertion(+)

git_19

修正が問題ないことを確認したら、master ブランチにそれをマージしてリリースする。

この際使用するのが git merge コマンド。

$ git checkout master
$ git merge hotfix
Updating 35c5302..73eb219
Fast-forward
 index.html | 1 +
 1 file changed, 1 insertion(+)

このマージ処理で “Fast-forward” というフレーズが表示されている。

これはマージ先のブランチ(master)が指すコミットがマージ元(hotfix)のコミットの直接の親であるため、Git がポインタを前に進めたため。

あるコミットに対してコミット履歴上で直接到達できる別のコミットをマージしようとした場合、Git は単にポインタを前に進めるだけで済ませ、この処理のことを “fast forward” と言う。

変更した内容が、これで master ブランチの指すスナップショットに反映されたので変更をリリースできる。

マージした結果、master ブランチの指す先が hotfix ブランチと同じ場所になる。

git_20

master ブランチが hotfix ブランチと同じ場所を指しているので、もはや hotfix ブランチは不要なので、 hotfix ブランチを削除しておく。

削除するには git branch で -d オプションを指定します。

$ git branch -d hotfix
Deleted branch hotfix (was 73eb219).

git_21

先ほどまで作業をしていたブランチ(chg01)に戻り、作業を続ける。

$ git checkout chg01
Switched to branch 'chg01'

作業が完了し、コミット。

$ git commit -a -m 'finished the change [chg01]'
[chg01 fabf224] finished the change [chg01]
 1 file changed, 1 insertion(+), 1 deletion(-)

git_22

ここで、hotfix ブランチ上で行った作業は chg01 ブランチには含まれていないことに注意。

もしそれを取得する必要がある場合、git merge master で master ブランチの内容を chg01 ブランチにマージ(統合)する。

またはそのまま作業を続け、いつか chg01 ブランチの内容を master に適用することになった時点でマージ(統合)する。

マージの基本

ブランチ(chg01)での作業を終えて、master ブランチにマージする準備ができたら、マージ先のブランチに切り替えてから git merge コマンドを実行する

$ git checkout master
$ git merge chg01
Merge made by the 'recursive' strategy.
 text01.txt | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

今回の場合、開発の履歴が過去のとある時点で分岐しているため、先ほどの hotfix のマージとは異なる表示になっている。
(Merge made by the ‘recursive’ strategy.)

マージ先(master)のコミットがマージ元(chg01)のコミットの直系の先祖ではないため、各ブランチが指すふたつのスナップショットとそれらの共通の先祖との間で三方向のマージを行われたため。

Git が共通の先祖を自動的に見つけ、ブランチのマージに使用する。

git_23

単にブランチのポインタを先に進めるのではなく、Git はこの三方向のマージ結果から新たなスナップショットを作成し、それを指す新しいコミットを自動作成する。これはマージコミットと呼ばれ、複数の親を持つ特別なコミットとなる。

git_24

これで、今までの作業がマージできたので、chg01 ブランチは不要になり削除することができる。

$ git branch -d chg01

マージ時のコンフリクト

同じファイルを2つのブランチで別々に変更してそれをマージしようとすると、Git はうまくマージする方法を見つけられないのでコンフリクトが発生し、以下のようなメッセージが表示される(マージに失敗しました。コンフリクトを修正(解決)してコミットしてください)。

$ git merge chg01
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

コンフリクトを解決するまで、処理は中断される。

コンフリクトが発生してマージできなかったのがどのファイルなのかを知るには git status を実行。

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

コンフリクトが発生してまだ解決されていないものは Unmerged paths: として表示される。

Git は、標準的なコンフリクトマーカーをファイルに追加するので、ファイルを開いてそれを解決しなければならない。コンフリクトが発生したファイルの中には、以下のような部分が含まれている。

index.html ファイル

<<<<<<< HEAD
<p>Fixed the problems</p>
=======
<div id="footer">Footer added</div>
>>>>>>> chg01

これは、HEAD (merge コマンドを実行したときにチェックアウトしていたブランチなので、ここでは master となる) の内容が上の部分 (======= の上にある内容)、そして chg01 ブランチの内容が下の部分に表示される。

コンフリクトを解決するには、どちらを採用するか等を判断する必要がある。この例では以下のように書き換える。

<p>Fixed the problems</p>
<div id="footer">Footer added</div>

このような解決を各部分に対して行い、<<<<<<< や ======= そして >>>>>>> の行をすべて除去する。

その後すべてのコンフリクトを解決したら、各ファイルに対して git add を実行して解決済みであることを通知する。(ファイルをステージすると、Git はコンフリクトが解決されたと見なす。)

git status を実行して、コンフリクトが解決されたこと(All conflicts fixed)を確認して、git commit を実行してマージコミットを完了させる。

$ git add index.html

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)
Changes to be committed:
        modified:   index.html
               
$ git commit
[master 55a5053] Merge branch 'chg01'

コンフリクトが解決し作業がマージできたので、chg01 ブランチは不要であれば削除することができる。

$ git branch -d chg01
Deleted branch chg01 (was fabf224).

参考元:Git のブランチ機能 – ブランチとマージの基本/Pro Git

ブランチの管理

git branch コマンドは、何も引数を渡さずに実行すると、現在のブランチの一覧を表示する。

$ git branch
  chg03
* master
  test

現在チェックアウトされているブランチに、* という文字が先頭についている。

各ブランチにおける直近のコミットを調べるには git branch -v を実行。

$ git branch -v
  chg03  d45dd01 change title [chg03]
* master 82b6ad1 Merge branch 'chg02'
  test   c8cffce lines added to test.txt [test]

現在作業中のブランチにマージ済みかそうでないかによる絞り込みができるようになっていて、以下のオプションがある。

  • –merged :現在作業中のブランチにマージ済みのブランチを調べる
  • –no-merged :まだマージされていない作業を持っているすべてのブランチを調べる

現在作業中のブランチにマージ済みのブランチを調べる

$ git branch --merged
  chg03
* master

この例では、少し前に master に chg03 ブランチをマージしたので、この一覧に表示されている。

このリストにあがっているブランチのうち先頭に * がついていないものは、通常は git branch -d で削除してしまって問題ないブランチ。

まだマージされていない作業を持っているすべてのブランチを調べる

$ git branch --no-merged
  test

先ほどのブランチとは別のブランチが表示される。(全てのブランチのマージが完了していれば、何も表示されない)

まだマージしていない作業が残っているので、このブランチを git branch -d で削除しようとしてもエラーになり削除できない。

$ git branch -d test
error: The branch 'test' is not fully merged.
If you are sure you want to delete it, run 'git branch -D test'.

本当にそのブランチを削除してしまってよいなら -D で強制的に消すこともでる。