Gitコマンドを理解するためにデータ領域について調べた

## Gitの3つのデータ領域について
Gitコマンドについて調べているうちに
CheatSheetを読めばGitコマンドが何をしているかなんとなく分かりそう
....な気がしたので、
CheatSheetを理解するため、コマンドの説明文を理解するためにデータ領域について調べた。

[Git CheatSheet](http://ndpsoftware.com/git-cheatsheet.html#loc=workspace;)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/253650/4cdd3ef0-be9b-24c5-10a3-e248a95cd8a7.png)


最初に見たとき、WORKSPACE、INDEXが何を示すのかすら分からなかったが、
このスライドが分かりやすかった。
[いつやるの？Git入門 v1.1.0](https://www.slideshare.net/matsukaz/git-28304397)

git cloneしたときにできるディレクトリが次のような構造だとしたら、
CheatSheetのWORKSPACE、INDEX、LOCAL REPOSITORYは、
それぞれ①ワークツリー(作業ディレクトリ)、②インデックス(ステージングエリア)、③Gitディレクトリを示す。

- .git　③
    - index　②
    - ...
    - ...
- app　　　　　　
- config
- public　　　　　　・・・・①git管理したいディレクトリ達
- resources
- ...

Gitコマンドは、データ領域間のファイル操作をするためのコマンドであり、
CheatSheetの左右に延ばされた矢印はそのことを表している。




#### そのほか
へぇーってなったけどまとめられなかった。

- HEAD　リポジトリの最後のコミット位置を表す。
- ワークツリー　現在の状態を表す。
    - コミット直後は、HEADとワークツリーが同じ状態になる。 
    - HEADとワークツリーの間にINDEXがある。これにより、変更点だけを選択してコミットできる。
- ブランチ　コミットの位置を表す、らしい。
- マージには2種類ある。
    - Fast-Forword(早送り)　ブランチをマージしたという履歴が残らなくなる。
    - Non Fast-Forword　いつもの。



## Git コマンド
[transitive.info Git 使い方 見出し一覧](http://transitive.info/article/git/)

#### リポジトリの作成
```
git init <project-name>
```
指定した名前のローカルリポジトリを新規作成する。
ワークツリー、インデックス、Gitディレクトリが生成される。

```
git clone <url>
```
リモートリポジトリをローカルに複製する。
 
#### 変更の作成
```
git status
```
差分があるかどうかチェックし、新規または変更のあるファイルを一覧で表示する。

```
git diff
```
ワークツリーとインデックスの差分、つまり、まだgit addしていないファイルの差分を表示する。

```
git add <file>
```
新規または変更のあるファイルをインデックスに追加する。
git add -u とすると、リポジトリに登録済みで変更されたファイルを追加するが、新規ファイルは無視される。
 
```
git cherry-pick <commit>
```
他のブランチの特定のコミットをコミットする。
cherry-pickしたときにコミットしたくない場合は、-rnオプションをつける。


#### コミットの修正
```
git reset <commit>
git reset --mixed <commit>
```
ワークツリーはそのままで、インデックスの変更を取り消す。
--mixedオプションはデフォルトで指定されるので、省略可。

```
git reset --hard <commit>
```
ワークツリー、インデックスをHEADに戻す。ワークツリー、インデックスの変更が消える。

```
git rebase <commit>
```
rebaseは使ったこともないし、言葉で説明できない・・・。
原理については、このスライドが分かりやすい。
[こわくない Git](https://www.slideshare.net/kotas/git-15276118)

以下のようなデメリットがあるので、基本的にgit mergeするべき。
①既にpushされている共有ブランチをrebaseすると、pushできなくなる。「1つ前のコミット」が書き換えられてしまうため。
②マージされたという履歴が残らない。
③コンフリクトが発生すると、コミット単位でコンフリクトを解消しなければならない。mergeと比べ、解消しなきゃいけない回数が増えて面倒くさい。

※オープンソースなどでは、rebaseしてからpushするのがマナーとされているらしい。ログがきれいになるから...？

#### 変更の同期
pull = fetch + merge/rebase

```
git fetch <remote_rep>
```
マージはせず、リモートリポジトリから変更を取得する。
git fetch git://example.com/rep.git branch:local_branch　とすると、
リモートリポジトリにあるブランチを取得し、ローカルのブランチとして保存できる。

```
git merge <branch>
```
他のブランチをマージしてコミットする。(マージコミット)

```
git push <repository> <local_branch:remote_branch>
```
push対象のリモートリポジトリと、
ローカルのどのブランチをリモートのどのブランチに送信するか指定し、
リモートリポジトリを更新する。

```
git pull
git pull <repository> <refspec>
```
リポジトリから変更点を取得して現在のブランチにマージする。
どのリポジトリから取得するかは、.git/config で指定するか、引数で指定する。


#### 一時保存 
未完成の修正を一時的に退避できる。
あるブランチでいろいろ作業したけど、別ブランチで修正をしたいときとかに使う。
Aブランチでの修正についてレビューを待つ間、Bブランチで別のタスクやる
↓
レビュー返ってきたからBブランチの修正は一旦stashしてAブランチに戻る、とか。

```
git stash save <message>
```
コメント付きで一時保存する。

```
git stash apply <stash>
```
指定した変更内容を復旧する。

```
git stash list 
```
一時保存した変更内容のリストを表示する。

```
git stash drop
```
直近で保存した変更内容を削除する。

## 参考
[Git CheatSheet](http://ndpsoftware.com/git-cheatsheet.html#loc=workspace;)
[GitHub Gitチートシート](https://services.github.com/on-demand/downloads/ja/github-git-cheat-sheet/)
[いつやるの？Git入門 v1.1.0](https://www.slideshare.net/matsukaz/git-28304397)
[こわくない Git](https://www.slideshare.net/kotas/git-15276118)
[transitive.info Git 使い方 見出し一覧](http://transitive.info/article/git/)