gitは怖くないと思い込むためのメモ

# 

## Gitの基本的な仕組み

Gitはスナップショットを記録する
### Gitのデータ構造
- ワークツリー
- ステージ
- リポジトリ


- git add
    - ファイル内容を圧縮（リポジトリ）
    - インデックスファイルにを作成（ステージ）
- git commit
    -  ツリーファイルを作成（リポジトリ）
    -  コミットファイルを作成（リポジトリ）

- リポジトリに「圧縮ファイル」、「ツリー」「コミット」ファイルを作成することでデータを圧縮している
- コミットが親コミットを持つことで変更履歴を辿ることができる
- Gitの本質はデータを圧縮して、スナップショットで保存していること
- Gitのコマンドは、そのデータに対して色々な操作をしている

### Gitを始める
gitリポジトリを作成する
 .gitディレクトリが作成される

```
git init


### Gitリポジトリのコピーを作成する


git clone <リポジトリ名>
```
例
git clone /home/git/sample.git

### 変更をステージに追加する

ステージは何のためにあるのか？

一部の変更を記録するためにステージは存在する。

```
git add <ファイル名>
git add <ディレクトリ名>
'git add .
```
### 変更を記録する（コミット）

```
git commit
git commit -m "<メッセージ>"
git commit -v
```
メッセージ付きで記録する

####コミットメッセージを正式に書くとき
１行目：変更内容の要約
２行目：空行
３行目：変更した理由

### 現在の変更状況を確認しよう
ワークツリーとステージ、リポジトリのファイルの状態を確認する

```
git status
```

### 何を変更したのか確認する
###変更差分を確認する
ワークツリーとステージ間の変更差分を表示する

```
git diff
git diff <ファイル名>
```

コミットとステージ間の変更差分を表示する

```
git diff --staged
```

### 変更履歴を確認する

```
git log
#１行で表示する
git log --oneline
# ファイルの変更差分を表示する
git log -p index.html
# 表示するコミット数を制限する
git log -n <コミット数>
```

### ファイルの削除を記録する

#### ファイルごと削除
 ```
git rm <ファイル名>
git rm -r <ディレクトリ名>
# ファイルを残したいとき
git rm --cached <ファイル名>
```
### ファイルの移動を記録する

####ファイルの移動を記録する

```
git mv <旧ファイル> <新ファイル>

# 以下のコマンドと同じ
mv <旧ファイル> <新ファイル>
git rm <旧ファイル>
git add <新ファイル>
```
### Git Hubにプッシュする
####リモートに追記する
```
git remote add origin https://github.com/user/repo.git
```

####リモートへ送信する
```
git push <リモート名> <ブランチ名>
git push origin master
git push -u origin master
```
-uオプションはorigin masterを登録することで次回のpushはgit pushで行うことを可能にする

###GitHubの画面を確認する
###コマンドにエイリアスをつける
```
git config --global alias.ci commit
git config --global alias.st commit
git config --global alias.br branch
git config --global alias.co checkout
```
### バージョンを管理しないファイルを無視する

- パスワードなどの機密ファイル
- 自動生成するファイル

```
# #から始まる行はコメント
# 指定したファイルを除外
index.html
#ルートディレクトリを指定
/root.html
# ディレクトリ以下を除外
dir/
# /以外の文字列にマッチ「*」
/*/*.css
```
### ファイルの変更を取り戻す
```
git checkout -- <ファイル名>
git checkout -- <ディレクトリ名>
# 全変更を取り消す
git checkout -- .
```
-- をつけるのはファイルと判定するため

###ステージした変更を取り戻す

```
git reset HEAD <ファイル名>
git reset HEAD <ディレクトリ名>
# 全変更を取り消す
git reset HEAD .
```

ワークツリーの変更には影響を与えない
リポジトリからステージに最新のコミットを反映させる
(ステージされた内容が元に戻る）

###直前のコミットをやり直す
```
git commit --amend
```
※リモートリポジトリにpushしたコミットはやり直したらダメ

###リモートの状態を確認しよう
####リモートを表示する
```
git remote
# 対応するURLを表示する
git remote -v
```
###リモートリポジトリを追加する
リモートリポジトリは複数登録することができる
####リモートリポジトリを新規登録する
```
git remote add <リモート名> <リモートURL>
git remote add tutorial https://github.com/user/repo.git
```
###リモートから取得しよう
####リモートから情報を取得する（フェッチ）
```
git fetch <リモート名>
git fetch origin
```
fetchとは取ってくるという意味
###リモートから取得しよう（プル）
####リモートから情報を取得してマージする(プル）
```
git pull <リモート名> <ブランチ名>
git pull origin master
# 上記コマンドは省略可能
git pull
# これは下記コマンドと同じこと
git fetch origin master
git merge origin master
```
###fetchとプルを使い分けよう
####プルの注意点
masterにいて何の変更もないときはpullするが、
基本的にはfetchを使うように運用ルールを決めておく
###リモートの情報を詳しく知ろう
```
git remote show <リモート名>
git remote show origin
```

###リモートを変更・削除する
```
git remote rename <旧リモート名> <新リモート名>
git remote rm <リモート名>
```

###ブランチって何？
並行して複数機能を開発するためにあるのがブランチ
他の人の影響を受けなくなる

####ブランチの仕組みを知る
コミットはスナップショット、コミットのIDを辿ることができる
ブランチはコミットを指したポインタにすぎない
コミットしたらブランチが指すコミットファイルが変わる
####ブランチとHEADの中身
ブランチはコミットIDを記録したポインタ
HEADは作業中のブランチへのポインタ
.git/HEAD
.git/refs/
に保存される

- 分岐することで複数の機能を同地並行で開発するための仕組みがブランチ
- ブランチとはコミットを指すポインタ
- ブランチの作成や切り替え、マージが他のバージョン管理ツールより高速
- 結果、Gitは大規模開発においてもっとも使われるツールとなり、普及した

###新しいブランチを作成する
#### ブランチの作成
```
git branch <ブランチ名>
git branch feature
```
#### ブランチの一覧を表示する
```
git branch
#### 全てのブランチを表示する
git branch -a
```
###ブランチを切り替える

#### ブランチを切り替える
```
git checkout <既存ブランチ名>
git checkout feature
# ブランチを新規作成して切り替える
git checkout -b <新ブランチ名>
```
-bオプションを使うとブランチを切り替えてくれる

###変更をマージしよう
#### 変更履歴を取り込む
```
git merge <ブランチ名>
git merge <リモート名/ブランチ名>
git merge origin/master
```
### マージには３種類ある
- Fast Foward:早送りになるマージ
 - ブランチのポインタを前に進めるだけ
- Autl Merge:基本的なマージ
 - 枝分かれして開発していた場合、マージコミットという新しいコミットを作る
 
- コンフリクト

### コンフリクトを解決する
ファイルの内容を書き換える
<< == >>の記述を書き換える

###コンフリクトがおきないようにするには

コンフリクト関連の事故が起きにくい運用ルール

- 複数人で同じファイルを変更しない
- pullやmergeする前に変更中の状態をなくしておく（commitやstashをしておく
- pullするときは、pullするブランチに移動してからpullする
- コンフリクトしても慌てない

### ブランチ名を変更・削除したい時

####ブランチを変更・削除する
```
git branch -m <ブランチ名>
git branch -m new_branch
```
```
git branch -d <ブランチ名>
git branch -d feature
# 強制削除する
git branch -D <ブランチ名>
```
###ブランチを利用した開発の流れ
masterブランチをリリース用ブランチ
開発はトピックブランチを作成して進めるのが基本

masterで開発するとバグが起こった時に戻すのが大変

####ブランチを利用した開発の流れ
開発したいトピックごとにブランチを切って開発を行う。
完了したら、masterにマージする。
###リモートブランチって何？
fetchした際に、origin/master等のリモートを参照するブランチが作られる

##GitHubを利用した開発手順
###プルリクエストの流れ
自分の変更したコードをリポジトリに取り込んでもらえるよう依頼する機能
####プルリクエストの手順
1. masterブランチを最新に更新
2. ブランチを作成
3. ファイルを変更
4. 変更をコミット
5. GitHubへプッシュ
6. プルリクエストを送る
7. コードレビュー
8. プルリクエストをマージ
9. ブランチを削除

###GitHub Flowの流れ
GitHub Flowとは、GitHub社のワークフロー
master→branch→プルリクエスト→master

1. masterブランチからブランチを作成
2. ファイルを変更しコミット
3. 同名のブランチをGitHubへプッシュ
4. プルリクエストを送る
5. コードレビューし、masterブランチにマージ
6. masterブランチをデプロイ

- masterブランチは常にデプロイできる状態に保つ
- 新開発はmasterブランチから新しいブランチを作成してスタート
- 作成した新しいブランチ場で作業しコミットする
- 定期的にpushする
- masterにマージするためにプルリクエストを使う
- 必ずレビューを受ける
- masterブランチにマージしたらすぐにデプロイする
- テストとデプロイ作業は自動化





###リベースする
```
git rebase <ブランチ名>
```
ブランチの起点となるコミットを別のコミットに移動するよ

####リベースの一連の作業の流れ
```
git checkout feature
git rebase master
git checkout master
git merge feature
```
Fast Forwardが起こりマージコミットが行われない

リベース（ベースが新しくなる）

mergeする際ファストフォーワードができる時はをfastforwardしないようにする設定
設定しておくとマージコミットのブランチの作業を残すことができる

```
git config --global merge.ff false
```
###リベースでしてはいけないこと
GitHub にプッシュしたコミットをリベースするのはNG
git push -f は絶対NG

###マージかリベースかは考え方次第
- マージ
　 - コンフリクトの解決が比較的簡単
　 - マージコミットがたくさんあると履歴が複雑化する

- リベース
  - 履歴を綺麗に保つことができる
  - コンフリクトの解決が若干面倒（コミットそれぞれに解消が必要）

運用
プッシュしていないローカルの変更にはリベースを使い、プッシュした後はマージを使おう
コンフリクトしそうなら、マージを使おう

###プルの設定をリベースに変更する

####プルのマージ型
```
git pull <リモート名> <ブランチ名>
git pull origin master
```
マージコミットが残るから、マージしたという記録を残したい場合に使おう
####プルのリベース型

```
git pull --rebase <リモート名> <ブランチ名>
git pull --rebase origin master
```
マージコミットが残らないから、GitHubの内容を取得したいだけの時は --rebaseを使おう

####プルをリベース型に設定する
```
git config --global pull.rebase true

# masterブランチでgit pullするときだけ
git config branch.master.rebase true
```
###リベースでコミットを書き換える
```
# 直前のコミットをやり直す
git commit --amend

# 複数のコミットをやり直す
git rebase -i <コミットID>
git rebase -i HEAD~3
```

HEAD~  とは
１番目の親を指定する
HEAD^２ とは
マージした場合の２番目の親を指定する

1. git rebase -i コマンドで対話的リベースモードに入る
2. 修正したいコミットをeditにしてコミットエディタを終了する
3. editのコミットのところでコミットの適用が止まる
4. git commit --amendコマンドで修正
5. git rebase --continueで次のコミットへいく
6. pickだとそのままのコミット内容を適用して次へいく

####コミットを並び替える、削除する
```
git rebase -i HEAD~3
```
コミットを削除したい場合は行を削除
ならべかえる。

####コミットをまとめる
squashを指定するとそのコミットを直前のコミットと１つにする

####コミットを分割する
```
git reset HEAD^
git add README
git commit -m 'README修正'
git add index.html
git commit -m 'index.html修正'
git rebase --continue
```
####git pullしたものをgit rebases してしまった場合

1. git rebaseでgithub上のコミットに戻す
2. git pull origin master

###タグの一覧を表示する
```
git tag
# パターンを指定してタグを表示する
git tag -l "201808"
```
### タグを作成する
####注釈付きタグ
```
git tag -a [タグ名] -m "[メッセージ]"
git tag -a 20180826 -m "version 20170520"
```
###軽量版タグ
```
git tag [タグ名]
git tag 20180826
# 後からタグ付けする
git tag [タグ名] [コミット名]
git tag 20180826 8a6c4d
```
タグのデータを表示する

```
git show [タグ名]
git show 20180826
```
###タグをリモートリポジトリに送信する

```
git push [ブランチ名] [タグ名]
git push origin 20180820
# タグを一斉に送信する
git push origin --tags
```
###作業を一時避難しよう
####作業を一時避難する
```
git stash
git stash save
```
stashは隠すという意味
変更分をstashに一時格納する

###避難した作業を確認する
```
git stash list
```
###避難した作業を復元する
```
#最新の作業を復元する
git stash apply
#ステージの状況も復元する
git stash apply --index
#特定の作業を復元する
git stash apply [スタッシュ名]
git stash apply stash@{1}
```
###避難した作業を削除する
#最新の作業を削除する

```
git stash drop
#特定の作業を削除する
git stash drop [スタッシュ名]
git stash drop stash@{1}
#全作業を削除する
git stash clear
```

## リモートに誤ってpushしてしまい、履歴ごと削除してしまいたい時

```
$ git reset --hard <戻したいコミットの番号>
$ git push -f <リモート名> <ブランチ名>
```