ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

Gitについて自分なりに説明してみた

友達に説明する必要があったのでGitの使い方を誤解を恐れずメモしておきます。自分の知識の整理も兼ねています。

この記事ではローカルマシン(一台のPC)での操作で完結しています。リポジトリの作成、コミットの作成、ブランチの作成、マージまでを範囲としています(これらの単語は順を追って説明していけたら、と思います)(ブランチの扱いは、最終的なリポジトリの形としてはgithub-flowです。)

Gitの概要

Gitは 分散型バージョン管理システム です。というとやばく聞こえますが、Gitを使う目的は 「大勢で1つのアプリケーションを一緒に作ること」 です。なのでそのために必要そうなバージョン管理機能がちゃんと備わっています。これあるべきでしょうとか予想しながら読んでいっていただけるといいかと思います。以下チュートリアルを通して概念と機能を説明していきます。

この記事を読み進めるために

  • 環境: Mac (他の環境の場合、概念と機能の説明は問題ありませんが、手順に関して読み替えが必要です)
  • 知識: ターミナルの基本的な操作 (自信がなくなった場合、こちらこちらを適宜参考にしながら読んでいただければ幸いです)

チュートリアルを始める前にちょっとした下準備を行います。

(下準備)gitコマンドがインストールされているか確認

今回は CLI での使い方を説明していきます。他の使い方としては、GUIアプリケーションなど沢山開発されているのでそれ経由で操作するのもありです。(その場合GUIアプリの解説ページに色々書いてあると思うので、この記事は閉じてしまって大丈夫です!)

Macを使っている場合、すでにGitがインストールされているかと思います。アプリケーションフォルダのユーティリティの中にある ターミナル.appを開いて、Gitがインストールされていることを確認してみましょう。ターミナルを開いたらgit --versionと入力して、実行してください。

$ git --version
git version 2.13.6 (Apple Git-96)

git version ...のような表示が出たらインストールされています。

$ git --version
-bash: git: command not found

と出たらインストールされていないので、ググってインストールしてください。

(下準備)Gitの初期設定

以下のコマンドを実行して、Gitのユーザー名、アドレスが登録されていることを確認してください。

$ git config user.name
ushumpei
$ git config user.email
mail@ushumpei.com

登録されていない(実行しても何も表示されない)場合は次のコマンドを実行してユーザー情報を登録しておいてください。

$ git config --global user.name "あなたの名前"
$ git config --global user.email あなたのアドレス

チュートリアル

リポジトリ作成

Gitによるバージョン管理はファイル単位で行われます。と言ってもコンピューターすべてのファイルを管理するわけではなく、管理する範囲は限定することができます。限定できる範囲はディレクトリ(フォルダ)単位で、Gitによって管理されるのはそのディレクトリに含まれているすべてのファイルになります。この限定された範囲を リポジトリ(repository) と呼びます。

実際にリポジトリを作ってみましょう。デスクトップにgit_tutorialリポジトリを作ります。

ターミナルで 1.デスクトップに移動 2.git_tutorialディレクトリの作成 3.新規ディレクトリ内へ移動 4.ディレクトリのgitリポジトリ化 を行います。TABキーでファイル名を補完したりして頑張ってください。

~$ cd ~/Desktop/
~/Desktop$ mkdir git_tutorial
~/Desktop$ cd git_tutorial
~/Desktop/git_tutorial$ git init
Initialized empty Git repository in /Users/ushumpei/Desktop/git_tutorial/.git/

Initialized empty Git repository in ...が出たら成功です。リポジトリが完成しました。

注意: もしかすると日本語環境の場合~/Desktopがないかもしれないです(この辺りは自信ないです)。~/デスクトップなど試してみてください。

git statusというコマンドを実行して見てください。このコマンドは現在のリポジトリの状態を表示してくれるものです。 とてもよく使います 、他のコマンドを打つ際もこのコマンドで実行前、実行後の変化の確認をしながらやると何をしているかわかってくると思います。

~/Desktop/git_tutorial$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

各行の意味は以下です。不明な単語については後ほど説明いたします。

  • 現在はmasterという ブランチ(branch)にいる
  • まだ コミット(commit) が存在しない
  • コミットの対象に含まれているものはない

Initial commit

管理下にあるファイルに対して、「誰が、いつ、なぜ、どのファイルの、どこの部分を、どのように変更したか(変更に関する5W1H)」という変更情報を管理するのがGitの大きな役割です。この変更情報は コミット(commit) と呼ばれます。コミットは開発者が好きな粒度で作成することができます、複数ファイルの変更を1つのコミットに含めるのが一般的です。

(コミットのイメージ)
変更理由: モバイルブラウザでトップページの挨拶文の表示が崩れてしまっていたので修正
日付: 2017/11/27
変更者: ushumpei
index.htmlというファイルの12行目を`<p>こんにちは</p>`から`<h1>こんにちは</h1>`に変更
stylesheet/mobile.cssというファイルを追加

コミットを作成する手順は次のようになります;

  • 変更: リポジトリ内でファイルに関する変更を行う(作成、更新、削除のどれか)
  • ステージ: git addgit rmなどのコマンドで、どの変更内容を履歴に残したいかGitに知らせる
  • コミット: git commitコマンドで変更履歴を作成する

超個人的なイメージではGit管理下のファイルを変更したら「変更内容の紙が出てくる(変更) -> 変更に含めたい紙を束ねる(ステージング) -> キリのいいところで束を箱に入れる(コミット)」ということをやっている感じです。

では実際にファイルを作り、Gitの管理下に追加してみます。1.ファイルの作成 2.ファイルを追加対象に含める 3.追加の流れになります。git statusを使いながら1つ1つ変化を追って確認していきましょう。

~/Desktop/git_tutorial$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

先ほどと同じ状態です。

~/Desktop/git_tutorial$ touch index.html
# index.htmlが作成されたので、好きなエディタで開いて以下の内容を記述して保存してください(# は不要です);
# <html>
# <head>
#   <title>git_tutorial</title>
# </head>
# <body>
#   <p>Git Tutorial</p>
# </body>
# </html>
~/Desktop/git_tutorial$ 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)

git statusによると、依然としてコミットの対象に含まれているものはないですが、新しくindex.htmlというファイルが作成されていて、まだGit管理下に入っていないという情報が表示されています。

Git管理下に含めるにはgit addコマンドを実行してくださいという指示が括弧中に記載されているので実行します。

~/Desktop/git_tutorial$ git add index.html
~/Desktop/git_tutorial$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   index.html

git statusによると、コミットの対象に「index.htmlを新規作成した」という変更を追加する準備ができたことが表示されています。この状態をindex.htmlの変更が ステージ(stage) されていると言い、この変更のステージを取りやめることを アンステージ(unstage) すると言い、git rm --cached index.html(場合に応じてgit reset HEAD index.html)でGitに知らせることができます。

最後にステージされている変更からコミットを作成してみましょう。

~/Desktop/git_tutorial$ git commit -m "Initial commit"
[master (root-commit) c04dc8f] Initial commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.html
~/Desktop/git_tutorial$ git status
On branch master
nothing to commit, working tree clean

上記のように、追加に関する情報が表示されたら成功です。git statusの結果は変更を全く行なっていない状態に戻っているかと思います。

これで 変更->ステージ->コミット の1サイクルが終わりました。Initial commitの部分は変更理由を記述します。慣習としてリポジトリを作成した直後のコミットはInitial commitと書くことが多いです。

作成したコミットを見る: git log

作成したコミットを見て見ましょう。git loggit log -pを実行してください。

~/Desktop/git_tutorial$ git log
commit c04dc8ffd000dd7ba23b20177c208e9095901d19 (HEAD -> master)
Author: ushumpei <shumpei.uzawa@gmail.com>
Date:   Tue Nov 28 00:59:56 2017 +0800

    Initial commit

~/Desktop/git_tutorial (master)$ git log -p
commit c04dc8ffd000dd7ba23b20177c208e9095901d19 (HEAD -> master)
Author: ushumpei <shumpei.uzawa@gmail.com>
Date:   Tue Nov 28 00:59:56 2017 +0800

    Initial commit

diff --git a/index.html b/index.html
new file mode 100644
index 0000000..e69de29

上記のコマンドで過去に行なったコミット内容が全て確認できます。変更の詳細がいらない場合はgit log、詳細を見たい場合はgit log -p変更履歴が確認できます。

更新

続いてindex.htmlを更新してコミットして見ましょう。index.htmlをエディタで開いて以下のように修正してください。(6行目のpタグをh1タグに変更します)

...
  <h1>Git Tutorial</h1>
...

git statusを実行して変化を見てみてください。

~/Desktop/git_tutorial$ 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が変更されたことが表示されています。もしstageしたいなら先ほどと同様にgit add index.html、変更を破棄して最後のコミットの状態に戻したいならgit checkout index.htmlを実行してくださいという指示が書かれています。

ここでどんな変更が行われたかを確認するコマンドgit diffを使ってみましょう。

~/Desktop/git_tutorial$ git diff
diff --git a/index.html b/index.html
index 135d8e3..243ca88 100644
--- a/index.html
+++ b/index.html
@@ -3,6 +3,6 @@
   <title>git_tutorial</title>
 </head>
 <body>
-  <p>Git Tutorial</p>
+  <h1>Git Tutorial</h1>
 </body>
 </html>

index.htmlに対する変更が表示されています。先ほど行なった通り、pタグの行が削除され(- <p>Git Tutorial</p>)、h1タグの行が追加され(+ <h1>Git Tutorial</h1>)ていることがわかります。そのまんまですが、行頭の-は削除、+は追加の意味です。(差分は文字単位ではなく、行単位での表示となります)

この変更で問題ないのでステージしてコミットしましょう。

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

    modified:   index.html

~/Desktop/git_tutorial$ git commit -m "ページタイトルなのでh1にタグを変更"
[master 081f264] ページタイトルなのでh1にタグを変更
 1 file changed, 1 insertion(+), 1 deletion(-)
~/Desktop/git_tutorial$ git status
On branch master
nothing to commit, working tree clean

1サイクルが終わりました。これまで行なった作業を確認するために、git log --graphを実行してみてください。2つのコミットが追加されていることが確認できるかと思います。

~/Desktop/git_tutorial$ git log --graph
* commit 081f264cc85e5074a93f7304ba2febf9efb90bd9 (HEAD -> master)
| Author: ushumpei <shumpei.uzawa@gmail.com>
| Date:   Tue Nov 28 10:17:57 2017 +0800
| 
|     ページタイトルなのでh1にタグを変更
| 
* commit b80d4812cbde6655bee82bfa20127519e8826b81
  Author: ushumpei <shumpei.uzawa@gmail.com>
  Date:   Tue Nov 28 10:02:38 2017 +0800
  
      Initial commit

--graphオプションをつけて実行したので、2つのコミットが線で繋がって表示されています。これは ブランチ(branch) と呼ばれる概念に関係しています。

ブランチ(branch)

ブランチ(branch) について説明します。ブランチは連続したコミットの集まりです。先ほど作った2つのコミットはmasterブランチの先頭に追加されています、どんどんコミットを重ねてブランチ(枝)を伸ばしていくイメージです。

ブランチと呼ばれるからには 枝分かれ させることができます、ブランチの途中から別の ブランチを生やして そちらを伸ばしていくことができます。この機能により、ブランチを分けることによって複数の開発者が互いに影響を受けずに並列に開発を行っていくことができます。(あとで出てきますが、枝分かれしたブランチは好きなタイミングで他のブランチに合流させることができます)

リポジトリにどんなブランチがあるのかはgit branchコマンドで確認できます。

~/Desktop/git_tutorial$ git branch
* master

Gitリポジトリを作った直後、ブランチはmasterしかありません。先ほどのindex.htmlに関する変更はmasterに追加していました。masterから違うブランチを生やしてコミットを追加してみましょう。ブランチの作成はgit branch ブランチ名です。

# 一行目より現在masterブランチにいることがわかります
~/Desktop/git_tutorial$ git status
On branch master
nothing to commit, working tree clean

# stylingブランチを作成
~/Desktop/git_tutorial$ git branch styling

# ブランチ一覧にstylingが表示されています、「*」は現在いるブランチを表しています
~/Desktop/git_tutorial$ git branch
* master
  styling

# git checkout ブランチ名でstylingブランチに移動します
~/Desktop/git_tutorial$ git checkout styling
Switched to branch 'styling'

# 一行目より現在stylingブランチにいることがわかります
~/Desktop/git_tutorial$ git status
On branch styling
nothing to commit, working tree clean

# ブランチ一覧でも同様に確認できます
~/Desktop/git_tutorial$ git branch
  master
* styling

それではstylingブランチの先頭にコミットを追加します。スタイルシートファイルstyle.cssを作成して、index.htmlでそれを読み込んでスタイルを適用しましょう。

~/Desktop/git_tutorial$ touch style.css
# style.cssを好きなエディタで開いて以下の内容を記述して保存してください;
# h1 {
#   color: #727272;
#   font-family: monospace;
# }
#
# index.htmlは次のようにheadタグ内にlinkタグを追加してください;
# <html>
# <head>
#   <title>git_tutorial</title>
# + <link rel="stylesheet" href="./style.css" />
# </head>
# ...
~/Desktop/git_tutorial$ open index.html # ブラウザで表示してみてもいいかもです

# 変更の確認をしましょう。index.htmlが変更され、style.cssが追加されています
~/Desktop/git_tutorial$ git status
On branch styling
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

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    style.css

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

# index.html、style.cssをステージします
~/Desktop/git_tutorial$ git add .

# 2つのファイル変更がステージされています
~/Desktop/git_tutorial$ git status
On branch styling
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   index.html
    new file:   style.css

# コミットします。現在stylingブランチにいるのでコミットはstylingブランチの先頭に追加されます(stylingブランチが1つ伸びます)
~/Desktop/git_tutorial$ git commit -m "スタイルシートを追加"
[styling 59df46b] スタイルシートを追加
 2 files changed, 5 insertions(+)
 create mode 100644 style.css

コミットが追加されました。ブランチの形を確認してみましょう。

~/Desktop/git_tutorial$ git log --graph
* commit 59df46ba1df6e9a29584dd2ad2d95b79248f0409 (HEAD -> styling)
| Author: ushumpei <mail@ushumpei.com>
| Date:   Tue Nov 28 11:10:48 2017 +0800
| 
|     スタイルシートを追加
| 
* commit 081f264cc85e5074a93f7304ba2febf9efb90bd9 (master)
| Author: ushumpei <mail@ushumpei.com>
| Date:   Tue Nov 28 10:17:57 2017 +0800
| 
|     ページタイトルなのでh1にタグを変更
| 
* commit b80d4812cbde6655bee82bfa20127519e8826b81
  Author: ushumpei <mail@ushumpei.com>
  Date:   Tue Nov 28 10:02:38 2017 +0800
  
      Initial commit

3つめのコミットが今追加したものです。今は直線で表示されているので枝分かれ感が薄いですが、2つめのコミットからstylingブランチがmasterブランチから分かれて、1コミット分伸びたという情報が表示されています。このコミットの変更はmasterブランチには影響しません。そのことをmasterブランチに移動して確認してみましょう。ブランチの移動はgit checkout ブランチ名です。

# masterブランチへ移動
~/Desktop/git_tutorial$ git checkout master
Switched to branch 'master'

# 状態の確認
~/Desktop/git_tutorial$ git status
On branch master
nothing to commit, working tree clean

# ファイルの確認
~/Desktop/git_tutorial$ ls
index.html

先ほど追加したファイルstyle.cssが存在しないことがわかります。またmasterブランチ上でgit logを行うとまだコミットが2つしかないことが確認できます。

~/Desktop/git_tutorial$ git log
commit 081f264cc85e5074a93f7304ba2febf9efb90bd9 (HEAD -> master)
Author: ushumpei <mail@ushumpei.com>
Date:   Tue Nov 28 10:17:57 2017 +0800

    ページタイトルなのでh1にタグを変更

commit b80d4812cbde6655bee82bfa20127519e8826b81
Author: ushumpei <mail@ushumpei.com>
Date:   Tue Nov 28 10:02:38 2017 +0800

    Initial commit

(補足) なぜブランチを分けるか?全てmasterにコミットしないのはなぜ?

それは多くの場合、masterブランチは実際にユーザーが使っているアプリケーションのソースコードになることが多いからです。レビュー、テストを経て開発者みんなで合意したソースコードのみがmasterに存在します。なのでmasterブランチへの変更は完全な状態で行われなければいけません。作業途中のコードを追加するといったことは避けるべきです。しかし開発作業では区切りのいいところでコミットしていく方が、全てのコードを書き終わってからコミットする(ゲームをセーブしないでクリアするようなものです)よりも断然楽です。なので開発作業を行う場所として新たにブランチを作成し、完成したらmasterにマージするというのがより優れた方法です。

マージ(merge)

現在このリポジトリには2つのブランチが存在しています。masterstylingです。流儀にもよりますが、基本的にGitではmasterブランチに全ての作業が集約していきます。スタイル設定作業が一旦落ち着いたのでstylingで行なった仕事をmasterブランチに適応しましょう。この別のブランチの変更を別のブランチに適応する作業を マージ(merge) と呼びます。分かれていた枝をくっつけるイメージです。超個人的なイメージでは、masterブランチからstylingブランチの先っぽを掴んで、masterブランチにくっつけてぎゅっとコブを作る感じです。

stylingmasterにマージします。コマンドはgit merge --no-ff stylingになります(--no-ffはマージした時にコブを作るおまじないです。マージには3つくらい種類がありますが、この方法が複数人の開発では重宝されています)。この時どちらがどちらにマージされるかというのは重要で、自分がmasterブランチにいることを確認した上でマージを行なってください。

~/Desktop/git_tutorial$ git status
On branch master
nothing to commit, working tree clean

~/Desktop/git_tutorial$ git merge --no-ff styling # 実行後適当なエディタが開かれます。使い方が不明なら、vimなら`ZZ`、nanoなら`Ctrl + x`を入力してください
Merge made by the 'recursive' strategy.
 index.html | 1 +
 style.css  | 4 ++++
 2 files changed, 5 insertions(+)
 create mode 100644 style.css

マージが実行されました。git log --graphで履歴を見ると、4つのコミットが表示されています。このことはstylingブランチにあった「スタイルシートを追加」のコミットがmasterブランチに適応されたこと、マージしたという事実を示す新しいマージコミット(merge commit)が作成されたこと、を示しています。

~/Desktop/git_tutorial$ git log --graph
*   commit c45179e33ebf642db092e04130bbd981078cb6f9 (HEAD -> master)
|\  Merge: 081f264 59df46b
| | Author: ushumpei <mail@ushumpei.com>
| | Date:   Tue Nov 28 11:46:57 2017 +0800
| | 
| |     Merge branch 'styling'
| | 
| * commit 59df46ba1df6e9a29584dd2ad2d95b79248f0409 (styling)
|/  Author: ushumpei <mail@ushumpei.com>
|   Date:   Tue Nov 28 11:10:48 2017 +0800
|   
|       スタイルシートを追加
| 
* commit 081f264cc85e5074a93f7304ba2febf9efb90bd9
| Author: ushumpei <mail@ushumpei.com>
| Date:   Tue Nov 28 10:17:57 2017 +0800
| 
|     ページタイトルなのでh1にタグを変更
| 
* commit b80d4812cbde6655bee82bfa20127519e8826b81
  Author: ushumpei <mail@ushumpei.com>
  Date:   Tue Nov 28 10:02:38 2017 +0800
  
      Initial commit

まとめ

長い文章を読んでくださってありがとうございました。またはまとめを見てくださってありがとうございます。とりあえず基本的な概念の説明を自分なりにまとめて見ただけです。わかりにくい部分、間違っている部分、お気づきになりましたらお知らせ下さい。(コメント、メール、twitter#など最大限対応します)

おまけ

  • リポジトリ(repository)は、枝分かれしたブランチ達を持っている(木みたいなもの)
  • ブランチ(branch)は、連続したコミット達から成り立っている(枝みたいなもの)
  • コミット(commit)は、複数ファイル達に対する変更履歴で出来ている(コブみたいなもの)

といった形です。Gitはこれら3つの対象に対して、様々な操作を行える機能を提供してくれるツールです。Gitは 分散型バージョン管理システム でその目的は 「大勢で1つのアプリケーションを一緒に作ること」 です。今回は バージョン管理システム の側面をクローズアップしてましたので、次回は 分散型 と言われる所以となる機能について書きたいと思います。