[Git]初心者がよく使うGitコマンド仕組みまとめ[備忘録]

# Gitの仕組みがよく分からなかった頃
Gitはコマンド打てば何となくでも動かせますが、よく分からないままローカルやリモートのファイルが書き変わるのは滅茶苦茶怖くないですか・・・。
そこで、仕組みを理解を深めるために自分用の備忘録を作成しました。間違いなどあればご指摘ください。

# Gitとは
Gitは分散型バージョン管理システムと呼ばれています。
これは各PCとサーバー上に__スナップショット__を保存することで、多くの人が同時に開発するときにバージョン管理を楽にしてくれます。

__スナップショット__とは、ある時点の全てのファイルになります。
Gitでは時点間の差分ではなくスナップショットとして保存するので、ある時点への変更と今の変更を合わせるといった操作が容易に行えます。

## データの場所
Gitでは大きく分けると4箇所にデータが存在します。
ワークツリー、ステージ、ローカルリポジトリ、リモートリポジトリです。

### ワークツリー
普段作業している場所です。
例えば実装するとPCのどこかにファイルが置かれていてエクスプローラーから確認できますよね。
その場所をGitではワークツリーと呼んでいます。

### ステージ
スナップショットの保存対象になる変更を保持する場所です。
何故、ステージがあるかというと、ステージがないとワークツリーにある変更を全てのスナップショットになってしまうからです。
ワークツリーとリポジトリの間にステージという場所を用意しておくことで、ステージにある変更だけをスナップショットを保存する、ということができます。

### ローカルリポジトリ
各PCにあるスナップショット置き場です。

### リモートリポジトリ
サーバー上にあるスナップショット置き場です。
サーバーに置いておくことで、他の人とファイルを一か所に管理することができます。

## Gitコマンド

Gitを使い始めるとよく聞く単語が、add / commit / checkout / push / fetch / marge / pull あたりかなと思っています。
一つずつ簡単に説明していきます。
詳しくは、[難しいGitコマンドは、仕組みから理解してみよう](https://qiita.com/_ha1f/items/2dca1047c57d4f0bd465#%E3%83%9E%E3%83%BC%E3%82%B8-1) や [まずはGitの仕組みを理解することから](https://qiita.com/kyoyyy/items/161b6905f45bee2efe21#gitobjects)を見るとよいです。
実際のデータの動きは[Gitの仕組み](http://koseki.hatenablog.com/entry/2014/04/22/inside-git-1) から [Git Object Browser](http://koseki.github.io/git-object-browser/ja/#/step1/.git/)で確認できます。このサイトを見ればコマンドによってどんなことが起こっているか分かります。おすすめ。

### git add
ワークツリーにある実ファイルからスナップショットを作ってステージに追加します。
この時、PC上で何が起こっているかというと・・・

- 圧縮したファイル(blobオブジェクト)がローカルリポジトリの .git/objects内に保存される。
因みに .gitディレクトリはgit init(リポジトリを新規作成するコマンド)を実行したディレクトリ内に作成される。  

- 実ファイルと.git/objects内に格納されたファイル(blobオブジェクト)のマッピング情報が.git/indexファイルに記載される。
![gitadd.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245399/1ca1126d-0160-6282-9e5f-9cdf96dfcffb.png)

### git commit
ステージに追加されたスナップショットをローカルリポジトリに保存する。
この時、PC上で何が起こっているかというと・・・

- ディレクトリ構成情報(treeオブジェクト)をローカルリポジトリの .git/objects内に保存する。
- 具体的には、とあるディレクトリ下にあるファイルの名前、サブディレクトリ名、オブジェクトIDといった情報を保存する。

- コミット情報(commitオブジェクト)をローカルリポジトリの.git/objects内に保存する。
- 具体的には、treeオブジェクト、作成者、日時、メールアドレス、コミットメッセージと、直前のコミットを親として保存する。
そうすることで親を参照していくことで変更を辿ることができる。
![gitcommit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245399/439029c0-ce8e-5afd-8d4b-42cb3afa2ceb.png)

-----------
### ブランチについて
checkout / push / fetch / marge / pull　を説明する前に先にブランチについて簡単に確認しておきます。

__ブランチ__とは、Gitではあるコミットから分岐して開発するのですが、その分岐のことです。
ブランチの実態はcommitオブジェクトを指すポインタです。
commitやpullをすることでブランチが指すcommitオブジェクトが変わります。
ブランチの情報はローカルの .git/refs/headsに保存されています。

#### HEAD
自分が現在作業しているブランチ。
ローカルの .git/HEADにブランチの先頭を指すリファレンスのパス情報が保存されています。

#### リモート追跡ブランチ
ローカルリにあるリモートブランチの状態を反映しているブランチ。
リモートブランチの状態を反映しているだけなのでローカルでcommitすることはできません。
リモートリポジトリのmasterブランチのリモート追跡ブランチは、ローカルの .git/refs/remotesに保存されています。

---------
以下コマンドの説明ですが、このあたりから力が尽きたので、文字のみの説明で・・・。
詳しくは[【Git】リモートからの取得とリモートへの反映で行っていること(fetch,pull,push)](https://qiita.com/forest1/items/db5ac003d310449743ca#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E8%BF%BD%E8%B7%A1%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81)を見るとよいです。

### git checkout
指定するパラメーターによって挙動が異なります。
1. git checkout <ブランチ名>
HEADを指定したブランチへ切り替える。ワークツリーの内容もそのブランチの内容が反映される。
ローカルにブランチがないが、リモート追跡ブランチにある場合、ローカルにブランチが作られて、そのブランチがHEADとなる。
 .git/HEADとログとして.git/logs/HEADが更新される。

2. git checkout -- <ファイル名またはディレクトリ名>
指定したファイル、ディレクトリの最後のコミット内容をワークツリーへ反映する。
--を付けるとGit側でファイル名またはディレクトリ名であることが分かる。

### git push 
ローカルリポジトリの内容をリモートリポジトリに送信する。

### git fetch
リモートリポジトリの内容をローカルリポジトリのリモート追跡ブランチに反映させる。
ローカルの .git/refs/remotesにリモートにあるcommit オブジェクト、tree オブジェクト、blob オブジェクトがコピーされる。
ワークツリーには反映されないため注意。

### git merge
ローカルリポジトリの内容をワークツリーに反映させる。
マージには3種類ある。

- Fast Foward  
ブランチが分岐しない場合、ブランチが指すコミットのポインタを進めるだけになる。
- Auto Merge  
ブランチが分岐している場合、2つのブランチの最新のコミットをベースにcommitオブジェクトを作成する。
これはマージコミットと呼ばれる。
マージコミットは2つのブランチの最新のコミットを親になるため親を2つ持っている。
- conflict  
同じファイルの同じ行に対して異なる編集を行った場合に生じる。
どちらの編集を採用するかを手動で解決しなければならない。


### git pull 
git fetchとgit margeを同時にする。
ワークツリーでmasterブランチにいるのにdevelopの内容をgit pullするということもできてしまうので、今いるブランチとgit pull対象のブランチは確認すべき。

## Git管理してみよう
下記を参考に管理化する。
[ローカルのプロジェクトをGitHubへアップロードする方法](https://qiita.com/devzip8/items/28ac253ea295ad6c2b73)  
[既存のディレクトリをGit管理化して、それを基にリモートリポジトリを作る](https://naokibtn.hatenadiary.org/entry/20130217/1361120970)  

### Gitの設定を変える
[複数のgitアカウントを使い分ける](https://qiita.com/0084ken/items/f4a8b0fbff135a987fea)  
[Git の Commit Author と Commiter を変更する](https://qiita.com/sea_mountain/items/d70216a5bc16a88ed932)  


## 参考サイト
[難しいGitコマンドは、仕組みから理解してみよう](https://qiita.com/_ha1f/items/2dca1047c57d4f0bd465#%E3%83%9E%E3%83%BC%E3%82%B8-1)
[まずはGitの仕組みを理解することから](https://qiita.com/kyoyyy/items/161b6905f45bee2efe21#gitobjects)
[Gitの仕組み](http://koseki.hatenablog.com/entry/2014/04/22/inside-git-1)
[Git Object Browser part1](http://koseki.github.io/git-object-browser/ja/#/step1/.git/)
[Git Object Browser part2](http://koseki.github.io/git-object-browser/ja-bare/#/step1/.git/)
[【Git】リモートからの取得とリモートへの反映で行っていること(fetch,pull,push)](https://qiita.com/forest1/items/db5ac003d310449743ca#%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E8%BF%BD%E8%B7%A1%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81)
https://git-scm.com/book/ja/v1
udemyの[もう怖くないGit！チーム開発で必要なGitを完全マスター ](https://www.udemy.com/unscared_git/learn/v4/overview)はどういう仕組みでどんなコマンドがあるかまとめて知れるのでGit初心者におすすめ。