仕組みから理解するgit入門 第二回

[第一回はこちら](https://qiita.com/JugglerShu@github/items/f3a3d929b931e6fefb9d)

# 前回の課題の解説とポイント

**4つ目コミットとしてtext1.txtのファイルを削除したものを作成しましょう。ワーキングツリーとステージングエリアの状態をイメージすることが重要です。ステージングエリア内のファイルを消すには、git rm --cached [path]を利用します。コミットを作り終わったらtext1.txtを削除しましょう。**

ここでのポイントは**コミットはステージングエリアの内容が記録される**という点です。ワーキングツリーからファイルを消しただけでは、作成するコミットからはファイルは削除されません。
4つ目のコミットは以下のようにして作成できます。

     $ git rm --cached text1.txt           // ステージングエリアからファイルを削除
     $ git commit                          // コミットを作成

コミット作成後の状態は以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/7ea19138-998e-fda7-595f-7a367647a680.png)

ワーキングツリーにはtext1.txtが残っていますがこれはgitからすると現状管理されていないファイル（新しいファイルを作ったのと同じ様な状態）に見えています。最後にワーキングツリーから`rm text1.txt`で削除することで、HEAD,ステージングエリア、ワーキングツリーの状態が同じになります。

通常はワーキングツリーとステージングエリアから同時にファイルを消すことが多いので、その場合は以下のコマンドで削除できます。

     $ git rm text1.txt

今回わざわざ`--cached`を利用してもらったのは、ステージングエリアとワーキングエリアの違いをきちんと理解してもらうためです。普段はわざわざ`--cached`を使うことはないと思います。

**git logで4つすべてのコミットハッシュを確認しましょう**

これは特に説明の必要はないかと思います。今作成したコミットができていることを確認しましょう。

**git checkoutで3つ目のコミットにワーキングツリーを戻しましょう。text1.txtが存在することを確認しましょう。**

   3つ目のコミットハッシュを用いて

     $ git checkout 9a5249bf9f2b961b2a92be3e0208a182ad9bcb07

これで3つ目のコミットにワーキングツリーとステージングエリアが戻ります。その状態を図示すると以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/11787682-16c0-b13c-2cce-bc84785ca9c0.png)

 - 3つ目のコミットの後にコミットを作成するとコミットグラフがどうなるか考えてみましょう

さて、この状態で別のコミットを作成してみます。

     $ echo modify file > text1.txt
     $ git add text1.txt
     $ git commit

直後のコミットグラフの状態は、以下のようになります。コミットグラフが枝分かれしている部分がポイントです。新しく作られるコミットのParentはHEADが指しているコミットになるため、このようになります。この部分について今回詳しく見ていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/d48b0390-b47a-b16e-4729-c38d64d15c9f.png)


# 今回のポイント
前回までで基本的なコミットの作り方が分かりました。履歴を作成して、その状態に戻せるようになったのでバージョン管理ツールとしてすでに最低限のことはできていますが、コミットハッシュを覚えていなくてはいけないなど、まだ少し不便です。
今回はgit用いた開発シナリオで必ず利用するブランチについてまず説明したいと思います。ブランチが理解できればgitの理解で必要な概念の基礎部分は完成です。

後半はこれまで理解したこととgitのコマンドとの対応を見ていきます。新しい概念は出てきません。gitのさまざまなコマンドを用いて、これまでに理解したgitの概念を操作していたいと思います。

まだチーム連携の話はでてきません。一人でgitのバージョン管理操作を一通り理解するところまでやっていきます。

# コミットグラフとブランチ
前回の課題でコミットが枝分かれできることが分かりました。ここではこの性質を利用し、履歴を２方向に別々に伸ばしていき、最終的に統合する（つまり、Subversionでいうところのブランチの作成、マージ）部分を見ていきます。

## コミットグラフの枝分かれ

まずコミットグラフの枝分かれについて見ていきますが、**枝分かれ＝ブランチではありません!!**。とても重要なことなのですが、ここでわざわざ「コミットグラフのブランチ」ではなく「コミットグラフの枝分かれ」と言っているのには理由があります。**ここで説明するのは、まだgitのブランチではありません**

## コミットグラフを枝分かれさせる

課題でやった通り、一度いくつかのコミットを作成してき、後ろに戻って再度別の内容のコミットを作成すればコミットグラフは枝分かれします。もう一度やってみます。

     $ git checkout 9a5249bf9f2b961b2a92be3e0208a182ad9bcb07     // 前回の3番目のコミットをチェックアウト
     $ echo another modification > text2.txt
     $ git add text2.txt
     $ git commit              // 3番目のコミットの後に更にコミットを作成。この時点で枝分かれが発生する

コミットグラフは以下のようになります。（これ以降コミットメッセージ、Parentは図から省略します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/dd9342c3-d991-f26c-5622-63d3098fb8de.png)

全部で3つの履歴のパスが出来上がります。それぞれのコミットあとに更にコミットを作成していけば3つの履歴のパスが独立して進んでいくことになります。gitにおいては、コミットグラフを枝分かれさせることで複数の変更を同時に、他の修正に影響せず進めることができます。

## ブランチ

複数の修正を同時に進められることは分かりましたが、使い勝手は少し良くありません。何故かと言うと、コミットの数が少ないうちはいいのですが、多くなってくると、重要なコミットがどれだか分からなくなったり、そもそも、今開発している出発地点となるべきコミットがどれだか分からなくなってしまいます。

例えば、ある時点から3つの方向に枝分かれさせて、別々の機能を実装していたとします。このとき、3方向すべての先頭のコミットのコミットハッシュを覚えていなくてはいけません。どのコミットハッシュでどの機能を開発しているのかを覚えておかなくてはいけないのです。しかも開発が進んでコミットが追加された場合には、覚えておくべきコミットハッシュは変わってしまいます。これではコミットハッシュの管理だけで大変なことになってしまいます。

そこで、ブランチの登場です。ここまで理解するとブランチの説明は一瞬で終わります。

**gitにおけるブランチは興味のある（開発が進んでいる）コミットへのポインタ（別名）**

です。単に今ここを開発しているよ、というポインタ（目印）です。Pro Gitでも以下のように説明されています。

> Git におけるブランチとは、単にこれら三つのコミットを指す軽量なポインタに過ぎません。

ですので、**コミットグラフに枝分かれがなかったとしてもブランチは存在します**。

## ブランチを使って最初から

ブランチの動きを理解するために、再度リポジトリを初期化した状態から説明をしていきたいと思います。
新たにgitリポジトリを作成しましょう。

     $ mkdir MyProj2
     $ cd MyProj2
     $ git init

gitでは初期化するとデフォルトで`master`と呼ばれるブランチを用いて、ここからのコミットを追跡するようになっています。最初のコミットを作成して、その直後の状態を図示してみます。

     $ echo hello > text1.txt
     $ git add text1.txt
     $ git commit

ここでは、ワーキングツリーはあまり関係がないのでコミットグラフのみを図示します。`master`というポインタがいままでの図に追加されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/19154421-66eb-fbdc-7040-9f29ff315d8a.png)


もう一つコミットを作成すると以下のようになります。

     $ echo hello world > text1.txt
     $ git add text1.txt
     $ git commit

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/24627ec2-96bf-aa94-b1f7-4dc37ec7cfcb.png)


コミットを作成するとブランチが一緒に先に進んでいきます（追跡します）。

少し注意してほしいのはHEADとの関係性です。HEADは**masterブランチへのポインタ**となります。これまではコミットを直接指していました。前回までgitの基本的な動きを理解するためにHEADが直接コミットを指すような操作を行いましたが、通常の開発シナリオではHEADはいずれかのブランチを指すことになります。HEADがブランチを指している状態でコミットを作成するとブランチとHEADが同時に移動します。

ここでmasterとは別ブランチを作って修正を入れていきます。ちょっと丁寧すぎる気もしますが、一つ一つ図示していきます。

まず、別ブランチを作ります

     $ git branch my_branch

このコマンドでmy_branchというブランチを作成します。コマンドにはmy_branchがどこを指すべきかは指定していませんが、この場合HEADの位置に作成されます。（gitのコマンドではコミットの指定を省略すると自動的にHEADを指定したとみなされるものが多いです。）

コマンド直後の図は以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/51e83c1b-02a8-1aff-8589-9dda88715496.png)



my_branchを使ってコミットを追加していくためにmy_branchをcheckoutします。

     $ git checkout my_branch

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/1d8d5850-eee1-ee4e-c93b-4fc2f4157ac6.png)


これでHEADがmy_branchを指すようになります。`checkout`はワーキングツリー、ステージングエリアも更新しますが、今回はコミットが変わっていないので、この2つのエリアに変更はありません。（同じ内容で上書きされたと考えてもよいです。）

ここでコミットを作成します。HEADがmy_branchを指していることに注意すれば、新たなコミットが作成された後どうなるかは想像がつくと思います。

     $ echo another modification > text1.txt    // 適当な修正を入れて
     $ git add text1.txt
     $ git commit                               // コミットを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/51c3a566-044b-5acc-6da7-fb9b483978ff.png)

ここで、masterに戻り、ファイルを追加してみます。

    $ git checkout master                 // masterに移動。ワーキングツリーやステージングエリアも更新される
    $ echo 2nd file  > text2.txt
    $ git add text2.txt
    $ git commit

これにより、以下のようなコミットグラフが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/2441d120-9bd8-e511-450e-e25ada4bb6fd.png)


ブランチを使うことで、枝分かれしたコミットグラフのそれぞれの先頭を常に追跡できていることが分かると思います。ブランチに適切な名前を付け、それをcheckoutすることで簡単に自分が開発している部分に移動して、作業を続けることができます。

通常の開発ではコミットハッシュを直接指定することは少なく、ほとんどはブランチ名を利用して進めていきます。

よくgitによる操作で「○○ブランチ上で作業する」というような表現がありますが、それは○○ブランチをcheckoutして作業するということになります。内部的な表現をすれば、HEADが○○ブランチを指している状態で作業するということになります。


### マージ

ここで2つのブランチでの修正を一つに統合したいと思います。以下のコマンドで行います。

     $ git merge my_branch      // masterブランチ上で行う

これを行うと、コミットメッセージの入力を求められます。これはgitが作成する新しいコミットに付けるメッセージです。通常はこのマージでどの様な機能を取り込んだかなどを書き込みます。
gitは以下のような新たなコミットを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5636/a99a8249-3deb-f0da-d64b-68ea96617648.png)

マージを行うと2つのコミットを親とするコミットが出来上がります。これをマージコミットと呼びます。2つのブランチ間にコンフリクト（同じファイルの同じ場所の修正など）がなければ、gitが自動的に両方の修正を取り込んだコミットを作成してくれます。masterブランチ上でマージを行ったので、masterブランチが一つ進むことになります。

gitのマージおよびコンフリクトの解消は、詳しくやると時間のかかるテーマなので、詳細は後回しにしたいと思います。まずはこのようにマージできることを理解しておいてください。

最後に`git log --graph`でコミットグラフがどの様な形になっているか確認してみましょう。上の図と同じ様な形になっているはずです。（コンソール上では縦方向に表示されるので、どのコミットがどれに相当するか考えながら読んで見てください）

## ブランチの削除

ブランチの削除は簡単です。

     $ git branch -d my_branch
     Deleted branch my_branch (was b21a96d).

ブランチの削除というと少し慎重になりがちですが、**ブランチは単なるポインタである**ということを理解していれば、特に慎重になる必要がないことが分かります。ポインタなので簡単に削除し、作って、移動できます。間違って消してしまったら、再度コミットハッシュを用いて作れば良いです（上のコマンドの例だと`b21a96d`)

(条件によって削除できないブランチがあります。`-D`オプションで削除できますが、理解するまではやらないほうがよいです。この辺りは後ほどで詳しく説明します。）


## 便利なコマンドと操作

ここまでのところでコミットの作成、操作について必要な概念の理解は完了しています。
あとは、このgitを使ってできることを自由に楽しく利用してバージョン管理をしてもらえればよいです。

ただ、そのためにはワーキングツリー、ステージングエリア、コミットグラフを自由に操作できるようにならないといけません。決まりきったシナリオの中で必要な操作だけをコマンドで行いましたが、実際には、これまでにない操作をする必要を感じると思います。
いままで理解した概念上でできることであれば、それに対応する形でコマンドも用意されています。ここからはよく利用するgitのコマンドをこれまで理解したことと合わせて見ていこうと思います。

ここで紹介する以外にも便利なコマンドやオプションがたくさんありますので、なんかコマンドが使いづらいなと思ったら適切なコマンドやオプションが無いか調べてみるといいと思います。

### コミットの指定の仕方について
コマンドの詳細に入る前に、すべてのコマンドに共通するコミットの指定の仕方について説明します。

容易に想像できると思いますが、gitコマンドにはコミットを指定するものが多くあります。例えば、`git log [commit]`は、指定されたコミットを起点に、親をたどってすべてのコミットの情報を列挙して表示してくれます。
ほとんどの場合、コミットの指定にはコミットハッシュだけでなくブランチ、HEADなどのキーワードを指定することもできます。
たとえば、`git log my_branch`ならmy_branchの指すコミットを起点に情報を表示します。

また、コミットハッシュを指定する場合でも、40文字すべてを指定せずに、先頭数文字を指定すればgitが自動的にマッチするコミットを探してくれます。小さなリポジトリであれば先頭6文字程度あれば、コミットを一意に識別できてしまいます。そのため、以下のように短縮してコミットを指定してもコマンドは適切に動作します。

    git log 796eb8            // 本来のコミットハッシュは796eb83fdbfab839f6310f45b2f356593e0a72ec

もう一つ、コミットを指定する方法でよく使うのがチルダ`~`です。これはあるコミットの親コミットを表します。
以下のような感じです。

     HEAD~    現在のHEADの親コミット
     9b3da3~  特定のコミットの親コミット
     HEAD~2   現在のHEADから、2つ戻ったコミット
     master~  masterブランチの親

例えば隣り合ったコミット同士のdiffを見たい場合には以下のようにできます。

    $ git diff 9b3ac4~ 9b3ac4

2つ前からの変更部分を知りたければ

    $ git diff 9b3ac4~2 9b3ac4
  
のようにします。


### 状態確認コマンド

まず最初にgitリポジトリの状態を確認するコマンドを見ていきます。3つありますが、実際の作業中は最もよく利用するコマンド類だと思います。

#### git log
コミットの履歴を表示します。何も指定しないで実行するとHEADから親コミットにさかのぼって順にコミットの情報が表示されます。

例

     $ git log                   // HEADを起点に履歴表示                   
     $ git log -2                // HEADを起点に2つ分のコミットについて履歴表示
     $ git log my_branch         // my_branchを起点に履歴表示
     $ git log master --graph    // masterを起点に履歴をgraph形式で表示


#### git status
git作業中に最も利用するコマンドがこのコマンドです。
一言で言うと、以下の3つのエリアの比較情報を表示してくれます。

 - HEADのコミット
 - ステージングエリア
 - ワーキングツリー

要は、現在のファイルの修正状況が分かります。

実際に具体例を見てみます。

まず、適当なコミットをチェックアウトして状態を確認します。

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

このとき、HEADのコミットの内容と、ステージングエリア、ワーキングツリーの内容に差はありません。そのため何も表示されません。

ワーキングツリーに変更を入れてみます。
   
     $echo hello my world > text1.txt

そして、状態を確認します。

     $git status
     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:   text1.txt           // text1.txtが変更されている

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

ワーキングツリーのみに変更があるので、その情報が表示されています。一番最後の行にコミットする場合には`git add`を利用しろと書いてあります。`git status`では、その変更点を次にどうすればよいかのヒントが表示されるのでわからなくなったらこれを参考にすると良いです。

次にステージングエリアにコピーして、`git status`を見ます。

```
$ git add text1.txt
$ git status
On branch master
Changes to be committed:           // コミットに含まれる変更点 = ステージングエリアとHEADとの比較
  (use "git reset HEAD <file>..." to unstage)

        modified:   text1.txt
```

今度はコミットに含まれる修正として表示されました。表現は違いますが、要はチェックアウトしたHEADとステージングエリアの比較情報を表示してくれていることになります。

ここで、再度ワーキングツリーに変更を入れて、`git status`を見ます。

```
$ echo modification in working tree > text1.txt
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   text1.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:   text1.txt
```

これで、HEADの指すコミット、ステージングエリア、ワーキングツリーのすべての状態が異なるという状況が生まれます。
そのため、text1.txtが情報表示に2回出てきています。一つはHEADとステージングエリアの違い、もう一つはステージングエリアとワーキングツリーの違いによって表示されています。
ヒントに表示されるコマンドを使ってワーキングツリーをもとに戻したり、ステージングエリアをもとに戻したりもできます。下でそれらのコマンドについては紹介しています。

特定のディレクトリ下やファイルだけについてstatusを表示したい場合には

    $ git status [path]

で見られます。


#### git diff
コミットやファイルのdiffを表示します。与える引数によって、何を対象にdiffを見るかが変わります。

     $ git diff                        // ステージングエリアとワーキングツリーのdiff
     $ git diff --cached               // HEADとステージングエリアのdiff
     $ git diff [commit1] [commit2]    // 2つのコミット間のdiff
     $ git diff HEAD~ HEAD             // 現在checkoutしているコミットと一つ前のコミットの間のdiff


### 操作コマンド

操作コマンドは実際に使って覚えるほうが良いので、いくつかのシナリオに沿って課題をこなしながら見ていこうと思います。必要なコマンドの詳細はこのあとにリストしてあります。どういう操作をしたらよいか考えながら、コマンドを探して実行していってください。途中で間違っても、ほとんどの場合はもとに戻せます。`git status`なども用いながら状況を確認し、どのコマンドを利用していったらよいか考えてみてください。
これまで理解したこととコマンドをつなげることが目的なので、いろいろなコマンドを自由に試してください。方法がひとつだけとは限りません。各ステップにヒントのとなるコマンドは書いてありますが、具体的に必要なオプションなどは書いていません。適切なオプションを自分で探すようにしてください。

#### シナリオ1 : 変更点を確認しながら、一部だけコミットする
1. 新たなディレクトリを作成し、gitリポジトリを作成してください 
   `git init`

2. 適当なファイルを2つ(A,B)作成し、最初のコミットを作成してください。
   `git add`, `git commit`

3. ここで、A,Bに修正を入れる必要がでてきたとします。今回は適当な修正をA,Bに入れてください。どの様な修正が行われたかを`git diff`で確認してください。

4. 上の2ファイルをステージングエリアにコピーし、これから作成されるコミットにどの様な修正が入っているか確認してください。
   `git add`, `git diff`

5. ここで、２つのファイルのうちBのファイルに入れた修正は次のコミットに含めるべきではないことに気づきました。ステージングエリアのBもとに戻し（ワーキングツリーのBは戻さず）、Aの修正のみコミットしてください。
   `git reset`, `git  commit`

6. さらに、Bに入れた修正はやはり必要ないことが分かりました。ワーキングツリー内のBを元に戻してください。
   `git checkout`


#### シナリオ 2 : ブランチを利用した開発
1. 新たなディレクトリを作成し、gitリポジトリを作成してください 
   `git init`

2. 適当なファイルを2つ(A,B)を作成し、最初のコミットを作成してください。
   `git add`, `git commit`

3. ここで、A,Bを別々のブランチ修正していくことにしました。適当なブランチを作り、以下のようなコミットグラフを作成してください。`master`ブランチではファイルAに対して変更を2回、`branch1`ブランチではファイルBに対して変更を2回入れ、`master`ブランチ上で`branch1`をマージします。
`git branch`, `git checkout`, `git merge`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/075b0908-e39c-d77c-55d7-7dc9945ebc97.png)

4. 期待通りのコミットグラフができているか確認してください。
   `git log`

4. branch2を以下のコミットを指すように作成してください。
`git branch` or `git checkout`
![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/fcaae4c2-0972-fee7-1b6e-d7f5f73fd4f8.png)

5. branch2上でファイルCを作成してコミットし、masterにマージしてください。
`git commit`,`git checkout`,`git merge`

6. branch2を削除してください
   `git branch`

最終的なコミットグラフは以下のようになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/625fba15-5316-7caa-228a-3578a369ce0d.png)


#### シナリオ3 : 間違ったブランチに入れたコミットを修正

1. 新たなディレクトリを作成し、gitリポジトリを作成してください 
   `git init`

2. 適当なファイルを2つ(A,B)を作成し、最初のコミットを作成してください。
   `git add`, `git commit`

3. ファイルAに修正を入れて、コミットを作成してください。
以下のようなコミットグラフが出来上がります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/ada65911-ca53-5307-08df-d53dbd29ff59.png)

4. ここで、本来であればファイルAの修正は新たなブランチを作成して入れたい修正だったことに気づきました。`master`を元の位置に戻して、3.で作成したコミットに`my_branch`が来るようにしてください。方法はたくさんあります。ヒントとして1つの手順を示します。

- `my_branch`を現在のHEADの位置(3.で作成したコミット)に作成する
- `git reset`を用いてHEADと`master`を1つ前のコミットに移動させる

最終的なコミットグラフは以下のようになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/9cbaacc0-fc84-811e-3b66-5479eb589e95.png)


### 操作コマンドリスト

リファレンスとして一部のコマンドを図で対応させておきます。詳細は以下の説明を確認してください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5636/eba787ec-90f5-b06f-b51f-9501d7cc0824.png)


#### git add / git rm
ファイルの追加(コピー)、削除、ワーキングツリーおよびステージングエリアで行います。オプションによってどのエリアのファイルが対象になるかが決まります。

     $ rm text1.txt      // ワーキングツリーのファイルを削除(gitコマンドではない)
     $ git rm text1.txt  // ワーキングツリー、ステージングエリアのファイルを削除
     $ git rm --cached text1.txt  // ステージングエリアのファイルを削除
     $ git rm -r [dir]   // ワーキングツリー、ステージングエリアの指定ディレクトリ下すべてを削除

#### git checkout

ワーキングツリーの内容を更新するコマンドです。
`git checkout`は動作の一貫性が乏しいコマンドで、与える引数によって根本的な動作パターンが変わります。大きく2つの別々の動作します。

**動作パターン1 : ブランチを指定して、ワーキングツリー、ステージングエリア、HEADを更新する**

あるブランチ（コミット）から作業を開始したい場合に利用します。オプションは特に必要なくただブランチを指定するだけです。ワーキングツリー、ステージングエリア、HEADが更新されます。

     $ git checkout [branch]
     $ git checkout -b [new_branch] [commit] //コミットに新しいブランチを作成してcheckout

**動作パターン2 : ファイルを指定してステージングエリアからワーキングツリーにファイルをコピーする**

ワーキングツリーに入れた修正を元に戻したい場合に利用します。ステージングエリアの内容でワーキングツリーを更新します。指定した引数がブランチでないことをgitに伝えるために`--`を引数に最初に指定します。

    $ git checkout -- [file1] [file2] [...] 


#### git reset
最も混乱しやすいコマンドです。ブランチ(HEAD)やワーキングツリー、ステージングエリアの更新を行います。これを利用するとワーキングツリーの内容を一切変えずにブランチだけ別コミットに移動させるなどができます。
完全に覚えるのは大変なので、重要なパターンだけとりあえず理解しておきましょう。

**重要なパターン : HEADの内容でステージングエリアを更新**

    $ git reset HEAD [file1] [file2]...

ステージングエリアに入れた修正をもとに戻したいときに利用します。

**その他のパターン**

その他は、ブランチを移動させたり、ステージングエリアを特定のコミットの内容で更新したりします。はっきり言って覚えるのは無理なので、こういうような操作ができることだけ知っておいて、使うときに調べて使いましょう。

    $ git reset [commit]              // 現在のHEAD,ブランチおよびステージングエリアを[commit]に更新
    $ git reset [commit] [file1] ...  // ステージングエリアのファイルを[commit]のファイルで更新
    $ git reset --soft [commit]       // HEADおよびブランチを[commit]に更新(ステージングエリア、ワーキングツリーに変更なし）
    $ git reset --hard [commit]       // HEAD、ブランチ、ステージングエリア、ワーキングツリーを[commit]に更新


#### git commit
コミットを作成します。

     $ git commit -m "message"    // messageをメッセージとしてコミットを作成 (メッセージ入力画面が出ない）
     $ git commit -a              // ワーキングツリーの内容でコミットを作成(git add, git rmをする必要がない)

#### git branch
ブランチに関する操作を行います。

以下のようにしてブランチに関する情報を表示します。

    $ git branch           // 存在するすべてのブランチを列挙
    $ git branch -v        // 存在するすべてのブランチとその詳細情報を列挙

ブランチを作成するには

    $ git branch [commit]  // [commit]の位置に新しいブランチを作成
で行います。

ブランチの削除には-dオプションを用いますが、少し注意があります。
   
    $ git branch -d my_branch

ブランチは、そのコミットが他のブランチの親（先祖）になっている場合には削除できますが、そうでない場合は削除できません。
これは、そのブランチを消してしまうと、そのコミットにたどり着く方法がコミットハッシュを覚えている意外になくなってしまうためです。
間違った操作をしないようにこうなっています。どうしても消したい場合には

    $ git branch -D my_branch

とします。

ブランチの削除はさほど神経質になる必要がないことは、ブランチの削除によって消されるのはポインタだけであることを考えれば分かるかと思います。もし間違って消してしまったらまた作ればよいです。


#### git stash

ワーキングツリー、ステージングエリアに加えた修正を一時的に退避します。それまでに加えた変更はリセットされますが、後から元に戻すことができます。

     $ git stash        // 変更を一時的に退避
     $ git stash pop    // 退避した変更を再度適用

stashは様々な使い方があるのですが、ここでは上のようなシンプルな使い方のみ紹介しておきます。

# まとめ

今回はgitの中心的な概念ブランチの理解と、さまざまなコマンドでの操作を見ていきました。コマンドは覚えようとせずに、コミットグラフやワーキングツリーなどの何を操作するためのコマンドなのかをイメージとして持っておき、具体的にやりたいことに合わせてオプションなどを調べながら使うのが良いと思います。

ここまでの内容でgitでできることのほとんどを理解しています。ここから先はこれらの応用に過ぎません。
次回はいよいよgitによるチーム開発を理解していきたいと思います。

[第三回はこちら](https://qiita.com/JugglerShu@github/items/55c278bdc615ee5e8f51)

# Q&A

### ブランチの名前の決め方はある？

まず基本としてgitでのブランチの仕方、及びブランチ名に関してはなんの制限もありません。自分で自由に決められます。一方である程度の規則性を持って使ったほうが、管理が楽になるのも確かです。よく参照されるのはhttps://nvie.com/posts/a-successful-git-branching-model/ です。いくつか参考になる命名規則を探して自分なりに決めれば良いと思います。

一つ注意してほしいのは、少なくともこの記事の中では今までのところ一人で開発をしていて、自分のリポジトリを持っているだけですので、ここでつけるブランチ名は自分だけ理解できればよいということです。そして本質的にはこのことはチーム開発になっても同じです。

チーム開発の部分で説明しますが、ブランチ（名）は本来的にはチーム内で共有されるものではありません（現実的にはコピーしていることが多いとは思いますが）。gitの良いところはリポジトリは自分のものであり、その中だけを自分でしっかり管理すればよいというものです。