Gitについて Part1

## はじめに
Gitについて調べたことを全3回でまとめていきます。

Part1のゴールは、個人がローカルリポジトリと
リモートリポジトリを使いこなせるための説明です。

そのうえで、今回は以下の2点を説明します。
1. Gitの仕組みを理解する
2. GitとGitHubを連携する

参考にしたサイト　[git book](https://git-scm.com/book/ja/v2)
（図はこちらのサイトから引用しています。ご了承ください）


## Gitの仕組み
### Git と SVN
バージョン管理ツールには大きく分けて
Git と SVN の2種類ある。
それぞれの違いを踏まえながら記載する。

|Git|SVN|
|:--|:--|
|分散バージョン管理<br>PCごとにサーバと同じデータを管理|集中バージョン管理<br>データをサーバで一元管理|
|スナップショット<br>変更箇所を含め、ファイルそのものを保存<br>ローカルで以前のバージョンに復元可能<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/2a882017-95ae-2735-00c9-6c09dbf1bfc8.png)|差分管理<br>基本バージョンからの差分を保存<br>サーバから以前のバージョンを取得する<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/efe59c6d-16de-c836-201a-8c92260bcbae.png)|

## Gitの3つのエリア
Gitを理解するうえで、3つのエリアがある。
**1. リポジトリ**
**2. ステージングエリア**
**3. ワークディレクトリ**

### リポジトリ
過去ソースコードの状態（スナップショット）を保存する場所のこと

・ローカルリポジトリ・・・自分のPC内のリポジトリ
・リモートリポジトリ・・・外部のサーバにあるリポジトリ(GitHubなど)

### ステージングエリア
現在修正したファイルをリポジトリへ登録するため、その変更内容を一時的に保存する場所

### ワークディレクトリ
ファイルを変更する等、実際にファイルの編集作業を行っているディレクトリのこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/3ae4be74-31d5-434e-0de4-17fb3d5feaff.png)

## Gitのワークフロー
1. 作業ディレクトリのファイルを修正。
2. 修正されたファイルのスナップショットをステージングエリアに追加。
3. ステージングエリアに追加に追加した内容をリポジトリに登録する（コミット）。

## 1. Gitコマンド ～基本～
### git init
・ローカルリポジトリを新規作成するコマンド
　Gitで管理し始めるためのコマンドで「.git」というディレクトリが作られる。
　このファイルでgitの管理に関するファイルがすべて入っている。

```bash:bash
$ git init
Initialized empty Git repository in XXXX.git/
```

### git clone
・既存のリポジトリのコピーをローカルに落とす（クローン）コマンド
　このコマンドを実行すると.gitフォルダを含めリモートリポジトリがクローンされる

```bash:bash
$ git clone <リモートリポジトリのURL>
Cloning into '<リモートリポジトリ名>'...
warning: You appear to have cloned an empty repository.
```
### git status
・各ファイルがそれぞれどの状態かを確認するコマンド
　ファイルの状態は3つある。（変更がない場合はUmmodified）

　1.Untracked（Gitが管理してない、新規のファイル）
　2.modified（Gitが管理していて、変更されているファイル）
　3.stageed（Gitが管理していて、git add されているファイル）

```bash:bash
$ git status
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/def033c3-b9a1-e433-acda-fda7d9dfd89b.png)

### git add
・ファイルをステージングエリアに追加するコマンド

```bash:bash
$ git add <ファイル名 or ディレクトリ名>
  git add -A （すべて）
```
### git commit
・ステージングエリアに追加したファイルをコミットするコマンド

```bash:bash
$ git commit 
  git commit -m "<メッセージ>"
```

・しかし、コミットをした後にコミットメッセージが間違っていた
　or コミット内容が違っていた。この時、2回のコミットではなく
　1回のコミット記録として残したい場合がある。（git logで確認）

・コメントのみ修正したい場合

```bash:bash
$ git commit 
  git commit -amend
　エディタが開くので、コミットメッセージを修正。
　上書き保存して、ファイルを閉じる。
```

・ファイルを修正したい場合
　まずファイルを編集する。

```bash:bash
$ git add -A
  git commit -amend
　エディタが開くので、コミットメッセージを修正。
　上書き保存して、ファイルを閉じる。
```

## Gitコマンド ～変更をもとに戻す～
### git checkout
・ワークディレクトリ内の変更内容の取り消し

```bash:bash
$ git checkout <ファイル名 or ディレクトリ名> 
$ git checkout .（すべて）
```

### git reset
・ステージングエリアにあげた変更内容の取り消し
（git add の取り消し）

```bash:bash
$ git reset HEAD <ファイル名 or ディレクトリ名>
$ git reset HEAD
$ git reset 

※指定した変更をステージングエリアから除外するのみ。
　ワークディレクトリ内のファイルが書き換わるのではない。
※git reset と git reset HEAD は同義
```

・コミットした変更内容の取り消し
（git commit の取り消し）

```bash:bash
$ git reset HEAD^ 
```

### HEADとは
現在チェックアウトしているブランチの先頭を指す。
こちらがすごくわかりやすい
( https://qiita.com/chihiro/items/d551c14cb9764454e0b9 )

## 2.Gitコマンド ～GitHubとの連携～

### origin と master について
- origin  : リポジトリ（URL）の別名
- master  : ブランチ名

**origin と master の名前はデフォルト**
**リモートリポジトリ作成時のデフォルト**

### git remote
・リモートリポジトリを名前を指定して追加する

```bash:bash
・リモート名という名でgitリポジトリを登録
$ git remote add <リモート名> <gitリポジトリ>

Ex.
$ git remote add origin https://github.com/XXXX.git

・リモートリポジトリを削除する
$ git remote rm <リモート名>

Ex.
$ git remote rm origin

・リモートリポジトリの一覧を表示する
$ git remote
origin

・リモートリポジトリの一覧をURL付きで表示する
$ git remote -v
origin  https://github.com/XXXX.git (fetch)
origin  https://github.com/XXXX.git (push)

・リモートリポジトリの情報を取得する
$ git remote show <リモート名>

・リモートリポジトリの名前を変更する
$ git remote rename <旧リモート名> <新リモート名>
```

### git push
・ローカルリポジトリの内容を、リモートリポジトリに反映する

```bash:bash
・リモート名という名でブランチに送信
$ git push <リモート名> <ブランチ名>

Ex.
$ git push origin master

・次回からgit pushだけで済むようにする
$ git push -u <リモート名> <ブランチ名>
```
### git fetch
・ローカルリポジトリへ情報を取得する

```bash:bash
・リモート名という名でブランチに送信
$ git fetch <リモート名/ブランチ名>

Ex.
$ git fetch origin master
```


### git merge
・ローカルリポジトリの情報をワークディレクトリに反映する

```bash:bash
$ git merge <リモート名/ブランチ名>

Ex.
$ git merge origin/master
```

### git pull
・ローカルリポジトリへ情報を取得すると同時に
　ワークディレクトリに反映する

```bash:bash
・リモート名という名でブランチ & ワークディレクトリに送信
$ git pull <リモート名> <ブランチ名>

Ex.
$ git pull origin master

・上記と同じコマンド
1. $ git fetch <リモート名> <ブランチ名>
2. $ git merge <リモート名> <ブランチ名>
```

## 3.Gitコマンド ～便利なコマンド～
### git diff
・ファイルの差分を確認するコマンド

```bash:bash
・ワークディレクトリとステージングエリアの比較
$ git diff
  git diff <ファイル名>

・ステージングエリアとリポジトリの比較
$ git diff --staged 
  git diff --staged <ファイル名>
```

### git rm
・ファイルを削除するコマンド

```bash:bash
・リポジトリ、ワークディレクトリの両方にある内容を消す
$ git rm <ファイル名>
　git rm -r <ディレクトリ名>

・リポジトリの内容のみ消し、ワークディレクトリを残す
$ git rm --cached <ファイル名>
```
### git log
・コミット履歴を確認する
　確認完了後はQきーで終了する

```bash:bash
・すべてのコミット履歴を見る
$ git log 

・すべてのコミット履歴を1行ずつのコミット履歴で見る
$ git log --oneline

・最新の変更からx個前のコミット履歴を見る
$ git log -n x
```

### git mv
・ファイルの名前を変更する

```bash:bash
・ファイル名の変更
$ git mv <旧ファイル> <新ファイル>

・上記と同じコマンド
$ mv <旧ファイル> <新ファイル>
$ git rm <旧ファイル>
$ git add <新ファイル>
```

### git config
・configフォルダに保存される情報を設定する

```bash:bash
・リモート名という名でブランチに送信
$ git config --global <設定項目> "内容"

Ex.
$ git config --global user.name "Miyasako"

・すべての設定を確認する
$ git config --list
```

### 「.gitignore」ファイル
・ファイルがある場所をルートディレクトリとし、
　指定したファイルをgit管理から除外する

```text:gitignore
・ディレクトリを問わず、sample.txtを除外
sample.txt

# .gitignoreが置かれたディレクトリ内のsample.txtを除外
/sample.txt
```
詳細は以下が分かりやすい。（ http://www-creators.com/archives/1662 ）

## 4. GitとGitHubを連携する
GitHubとGitの連携のやり方は以下の手順で実施する

### 1. GitHub上でリポジトリを作成する
1. GitHubにログインする
2. 「New Repository」ボタンを押下する
3. 「Repository name」を入力する
4.  公開/非公開、概要などを入力
5. 「Create repository」で作成完了

### 2.GitHubのリポジトリをクローンする
1. 対象のローカルフォルダで
```git init``` or ```git clone``` を行う。

### 3.ローカルで編集した内容をGitHubにアップロード
1. ローカルでファイルを編集する
2. コマンド```git add -A```を行う
3. コマンド```git commit```を行う
4. コマンド```git remote add origin <リポジトリのURL>```を行う
5. 5. コマンド```git push origin master```を行う

## 補足：gitのデータの持ち方
・git commitした場合に作成されるオブジェクトは３つある。
1. blobオブジェクト
2. ツリーオブジェクト
3. コミットオブジェクト

・3つのファイルを含むディレクトリをコミットした場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/233baa61-431b-a11d-d9f1-4fbf8dd1c761.png)

・変更を加えてコミットした場合のツリー（直近のコミットへのポインタが入る）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/c71f9500-8955-7469-154a-2b8203d45b5e.png)

### blobオブジェクト
・1つのファイルの中身が圧縮されたオブジェクト。
　ステージングエリアにgit addすると、addしたファイルが圧縮されてblobオブジェクトになる。
　「.git/objects」以下に格納される

・SHA-1 ハッシュというハッシュ値を計算して作成するため、同じ内容のファイルは同じハッシュ値になる。

```bash:bash
$ git cat-file -p master^{tree}
100644 blob 1c2e6eb9317f1786bb60b1a20d941fa725bb7523    sample.txt
100644 blob 2a412606369d7a1b3eb5c53514ba3f5de3a02602    sample_github.txt
```

### ツリーオブジェクト
・ディレクトリの中身の一覧と、どのファイルがどのblobに対応するかを表すオブジェクト
　下記図のようにツリーオブジェクトは「blobオブジェクト」と「ツリーオブジェクト」
　が格納されており、ディレクトリの1階層ごとに1つのツリーファイルが作成される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418028/97587cb1-084e-6c19-4f49-ad25074b0dc6.png)

```bash:bash
$ git cat-file -p master^{tree}
040000 tree b660134185b180a6827424797a8a3526fc770944    new_folder
100644 blob a3ff572543d64d658e113922453473906b19a8c1    sample.txt
100644 blob 2a412606369d7a1b3eb5c53514ba3f5de3a02602    sample_github.txt

$ git cat-file -p b660134185b180a6827424797a8a3526fc770944
100644 blob a3ff572543d64d658e113922453473906b19a8c1    sample2.txt
```

### コミットオブジェクト
・コミットした時点のメタデータが入っている。
　メタデータの中身は以下の通り

- トップレベルのツリーオブジェクト（tree）
- 一つ前のコミット（parent）
- 作者のuser.name/user.email
- コミッターのuser.name/user.email
- 空行
- 一つ前のコミットメッセージ

```bash:bash
$ git cat-file -p HEAD
tree c1003506f3efc11d16f0c9ab6f7e63f30ae88756
parent 66f83c3b6ca576467c6a3d0578c7f5320663c4b7
author ShoheiMiyasako <shohei.miyasako@gmail.com> 1565766982 +0900
committer ShoheiMiyasako <shohei.miyasako@gmail.com> 1565766982 +0900

フォルダを作成

・さらに１つ前のコミットオブジェクト
$ git cat-file -p 66f83c
tree 979925e5852c4980b4c8e93193fff43bf7a87b43
parent 0a702cdea8f9ea002c5ea03d296abfb57258c4e7
parent 3e70f7465f6c3c5fed053495c2708fd17cbd4319
author ShoheiMiyasako <shohei.miyasako@gmail.com> 1565745981 +0900
committer ShoheiMiyasako <shohei.miyasako@gmail.com> 1565745981 +0900

Merge remote-tracking branch 'origin/master'
```

## おわりに
私のまとめが参考になれば幸いです。
以上です。