初心者によるGit基本の使い方まとめ

# 初めに
Gitの勉強ノート整理しながら文章が長くなりすぎて、GitやGitHubの使い方を分けてまとめて行こうと思います。今回はローカルでGitをどう使っていくか自分なりにまとめました。

# OS環境&ツール
- Windows 10
- Git-bash 2.35.1.windows.2

# GitとGithub

Git：バージョン管理システムというソフトウェア。（Local）

GitHub：Gitを利用した開発者たちへのWebサービスプラットフォーム。（Remote）

# Local Operations - Three Stages of Git

以下は自分なりにまとめたものです。

ファイルが**Local Repository**までおおむね四つの状態に分けられています。

（PPTで作った図ですが、センスの無さですみません。）
![git3stages4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2477698/fd8ed322-d14d-c1a5-f7cf-6b8f5bf4958c.png)

**Working Directory**：追跡されていない。（Untracked）

**Staging Area（INDEXとも呼ばれる）**：”**git add**”でこのエリアに、コミットの一歩前です。（Tracked＆Staged）

**Modified**：一度”**git add**”でStaging Areaに置かれたけれど、編集のせいでしばらくModified付箋を付けて別のエリアに。（Tracked＆UnStaged）

**Git directory**：”**git commit**”でバージョンSHA-1が付与され、Local Repositoryで管理され、GitHubにpushする手前の状態です。（Committed）

# よく使われるGitコマンド一覧

## Local Repository
- git init
- git status
- git add
- git rm --cached & .gitignore（ファイル）
- git commit
- git log
- git checkout
- git reset --soft HEAD^
- git diff

（今回はLocal Repositoryの部分までまとめました。）

### git init　Git repository初期化
プロジェクト開発の初めは、バージョン管理のためGit Bashを使ってプロジェクトのディレクトリ先に移動する。
```
  # 注釈です。
$ pwd projects 　# pwdは現位置を示すコマンド
$ mkdir gitdemo 　# gitdemoというディレクトリを作る
$ cd projects/gitdemo 　# gitdemoに移動する
```
プロジェクト全体のバージョン一括管理したいから、一番上階層のディレクトリに”git init”を使用する。（開発環境によってディレクトリごとに”git init”を使って管理してもいいと思いますが、自分はいまだに小さなプロジェクトしか触れたことがなかったので、一括管理するのが多いです。）
```
$ git init　
```
すると、以下のような返す文が出てきます。
```
Initialized empty Git repository in /projects/gitdemo/.git/  # 空きのGit repositoryは初期化成功
/projects/gitdemo (master)  
```
**/projects/gitdemo (master)**
()の中はブランチ（branch）名ですが、masterは基本的に主要のブランチとしているが、開発環境によって違うときもあります。また、開発中ブランチ間やバージョン間に移動するのもよくあって、()の中をチェックすることでどこにいるかを把握できたらいいと思います。

もしコマンド使う場所間違えたら、
```
$ rm -r .git
```
で削除すればいいんです。（GUIで削除してもよいです。）

### git status　Git状態チェック
“**git init**”で初期化され、この状態で”**git status**”使うと
```
$ git status
On branch master  # 今masterブランチにいる
No commits yet  # まだ何もcommitしていません
nothing to commit (create/copy files and use "git add" to track) 
```
（ディレクトリにはファイルがないためcommitできるものはありません。ファイルを作るもしくはコピーして”**git add**”使って追跡を始める。）

### git add　Staged状態に移動
```
# 先にtouchでファイルを作る
$ touch app.js
$ touch index.html
$ touch stylesheet.css
$ git status

Untracked files:  # Untracked状態
(use "git add <file>..." to include in what will be committed)
app.js
index.html
stylesheet.css

nothing added to commit but untracked files present (use "git add" to track)
```
（Staged段階にいるものはありませんからcommitできない。Untracked段階にいるファイルを示す。”**git add**”を使って追跡を。）
```
$ git add app.js
$ git status
Changes to be committed:  # Staged状態
(use "git rm --cached <file>..." to unstage)  # “git rm --cached”使えばUntrackedに戻す。
new file:   app.js

Untracked files:  # Untracked
(use "git add <file>..." to include in what will be committed)
index.html
stylesheet.css
```
いちいち”**git add**”使うのが面倒だから、"**git add --all**”、または”**git add .**”使って

```
$ git add .
```

全員Stagedに。

また、子階層にいるディレクトリも”**git add**”が使えます。（空きのディレクトリなら表示されませんが。）

### git rm --cached & .gitignore　Git管理から外す
**git rm --cached**
公開されたくないファイルがあれば“**git rm --cached**”を使ってUntrackedに戻してもいいが、”**.gitignore**”を使ってもいいと思います！

**.gitignore**

Git管理にされたくないファイルやディレクトリなどを指定するファイルです。

```
$ touch .gitignore
$ code .gitignore  # codeはデフォルトエディターを開くコマンド
```

指定方法たくありますので、ここで自分がよく使う書き方をまとめてみました。設定範囲は**.gitignore**が存在するディレクトリ及びすべての子ディレクトリに適用する。
（ここはUnit testのファイルとディレクトリを管理たくない、ということを例にした。）
```
  # ファイル名またはディレクトリ名が一致すると無視する
test/  # ディレクトリ
app_test.js  # ファイル

  # パス指定で特定のファイルを無視
/projects/gitdemo/test/app_test.js/

  # パス指定で特定のディレクトリを無視
/projects/gitdemo/test/

  # 特定の拡張子を無視
*.exe  # "*"は任意文字ということで、任意の.exeファイル全部無視
```
注意書き：**.gitignore**はUntracked状態にあるファイルに適用する。"**git add**"でStagedになったファイル、または一度”**git add**”を使い、その後編集してmodified状態になったファイルには適用しません。”**git rm --cached**”か”**git restore**”でファイルをUntracked状態に戻したら無視できます。

またcommitの時 **.gitignore**ファイルも一緒にするべき、入れてなかったファイルもプログラム構成の一つにみなしていると思われますので。（←いままでの経験で個人的に解釈が含まれています。）

**参考資料はこちらです↓**
[github/gitignore: A collection of .gitignore templates](https://github.com/github/gitignore)
[.gitignore の書き方 - Qiita](https://qiita.com/inabe49/items/16ee3d9d1ce68daa9fff)

### git commit　新しいバージョンを作る！
```
$ git commit
```
これをそのまま入力したら、インストール時に選択したエディターが出てきます。
ここでは少しcommit messageについて書きたいと思います。commit messageの世界には暗黙のルールというものがあります。。調べたら自分なりに以下のようにまとめました。
#### commit message　基本概念

- 粒度（Granularity）
- 関連性
- 独立性

#### commit message　暗黙のルール

- 件名を大文字にする
- 件名を*命令文を使用する*
- *件名を50文字以内にする*
- *ピリオドで終了しない*

毎回のcommitは機能追加やバグ修正など一つ一つ独立の事件として、「What（何を）、Why（なぜ）、How（どのように）」程よく具体的に説明する。もちろんcommit messageをどう書いたほうがいいかという模範解答は存在していません。ここでのまとめも勉強ノートも一緒に働く者たち、そして未来の自分が見るとき、すぐこの独立事件の核心を掴めるように頑張りたいと思います。

**参考資料はこちらです↓**
[コミットメッセージについてのガイド - ITnews](https://itnews.org/news_contents/a-guide-on-commit-messages)


エディターを開かずGit Bashで直接commit messageを入れるのも可能です。
```
$ git commit -m "first commit"
```
![gitcm1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2477698/4065eb28-451a-daf5-a91a-8722de7e92df.png)
**[master (root-commit) 30ff845] first commit**
master：ブランチ名
root-commit：[初めてのcommit](https://alligator.io/workflow/git-commit-and-collab/#:~:text=root%2Dcommit%20means%20that%20this,new%20commit's%20unique%20ID%20number.)
30ff845：バージョンSHA-1
first commit：コミットメッセージ

**4 files changed, 0 insertions(+), 0 deletions(-)**
4 files changed：（前のバージョンと比べて）ファイル（ディレクトリも含む）4つが新しいバージョンを作った。
0 insertions(+)：新しく入れたのは0行。
0 deletions(-)：削除されたのは0行。
（insertionsとdeletionsはコード添削された行に指している。）

残りは、このバージョンに入ったファイルの詳細。（注：四つ目は子ディレクトリ）

一旦コミットしたファイルに修正入れたら”**git status**”でチェックすると、
```
On branch master
Changes not staged for commit:  # Modified状態
(use "git add <file>..." to update what will be committed)  # “git add”でStaged状態に
(use "git restore <file>..." to discard changes in working directory)  # “git restore”でUntracked状態に
modified:   app.js  # Modified状態のファイル

no changes added to commit (use "git add" and/or "git commit -a") 
```
（“**git add**”でStaged段階に、もしくは"**git commit -a**"でStaged段階飛ばして直接コミットする。）
```
$ git commit -a”  # エディターを開いてコミットする
$ git commit -am “任意文字”  # ターミナルでコミットする
```
注意書き：一度もcommitしていないファイルはこの方法に適用されていません。一度”**git add**”⇒”**git commit**”を経てからこの方法が使えるようになります。（つまりUntracked状態ではなく、Modified状態のファイルだけに使える。）
ちなみに、aはallということで、Modified状態のファイルを検知し、Staged状態にしcommit動作に移します。

#### git commit --amend
直前のcommitメッセージを変えたいときのコマンドです。エディターでメッセージ変更を保存したら最新のcommitになります。

### git log　各バージョンの履歴をチェック

書き上げたファイルに修正や新機能の追加など、または過去の編集履歴を確認するために”**git log**”を使えば、「いつ、だれ、編集後のメッセージ」が見られます。
```
$ git log --oneline  # 省略されたバージョンSHA-1とコミットメッセージだけ表示する
```
### git checkout　バージョン/ブランチ間に切り替え
一度ファイルの修正が終わったけれど、過去のあるバージョンのファイルを見て確認したいなあと思ったら、”**git checkout**”でバージョン間に切り替えることができる。
```
  # 今はmasterブランチにいる
$ git log  # 編集履歴をチェックしたうえ、バージョンSHA-1をコピーする
$ git checkout バージョンSHA-1  # これで過去のバージョンに戻れる
...
$ git checkout master  # masterブランチの最新バージョンに戻る
```
仮に、このプロジェクトにはfeatureというブランチがあれば
```
$ git checkout feature  # featureブランチの最新バージョンに移動する
$ git log  # 編集履歴をチェックしたらfeatureブランチほかのバージョンに
```
“**git checkout**”を使ったらバージョン間だけでなく、ブランチ間も自由に行けます。

"master"ブランチと言ってもデフォルトで設立されたブランチの名前の一つにすぎません。あるブランチに切り替えるとき、あくまでもそのブランチの最新バージョンに到着するわけです。
なので協力開発の場合はプロジェクトの主要ブランチはどのブランチか、どうやってマージするか、READ.MEファイルでチェックし、またはGitHub上の指示に従います。

#### git checkout --
すべての変更・編集履歴を捨てるコマンドです。
```
$ git checkout -- file_name  # 指定ファイルを前回commit時の内容に戻す。
$ git checkout -- .  # 全ファイルを前回commit時の内容に戻す。
```
### git reset --soft HEAD^　直前のcommitを取り消す
"**git reset**”は結構理解が難しいところがあって、ここもとりあえず自分なりにまとめてみました。

--soft：ソフトモード（Working DirectoryやStaging Areaの変更はそのまま残る）。
HEAD：今いるブランチ。（”**git log --oneline**”で今いるブランチが分かる。）
^：前回。（^^は前々回。3回からは~3など）
```
$ git reset --soft HEAD^  # commitの一歩前に戻りたいときに使う技です。
```
**参考資料はこちらです↓**
[git commit を取り消して元に戻す方法、徹底まとめ | WWWクリエイターズ](https://www-creators.com/archives/1116#1_git_commit)

### git diff　変更したところをチェック
ファイルの添削したところを見たいとき使うコマンドですが、未追跡（Untracked）のままだと見られないんです。
添削する前に、一度”**git add**”使って追跡（Tracked）状態になったのを前提として、
```
  # 再び”git add”使う前に、編集前後の違いを見るなら
$ git diff

  # ”git add”が使われStaged状態になったファイルが、前回commitした時との違いを見るなら
$ git diff --cached

  # 今回のcommitと一つ前のcommitの違いを見る
$ git diff HEAD^
```
参考資料はこちらです↓
[忘れやすい人のための git diff チートシート - Qiita](https://qiita.com/shibukk/items/8c9362a5bd399b9c56be)

# ここまでのまとめ（実践編）
```
  # ファイルの編集一段落がついてこれからバージョン管理を
$ git init  # 今のディレクトリでバージョン管理システムを使うことGitに通知する
$ touch .gitignore
$ code .gitignore  # 無視したいファイルやディレクトリのリストを書く
$ git add .  # 全員Staged状態に (Untracked状態には"git commit -am"使えません)
$ git status  # 少し状態確認してみる
$ git commit -m "First commit"  # 一回目のコミット、ここは適当にメッセージ入れた
$ git status  # 返す文"working directory clean"見て少し安心した

...しばらく作業してちょうどいい作業段階にコミットしようと、
$ git status  # 新しく作ったファイルがUntracked、一度コミットしたファイルが編集されてModified

... ".gitignore"に入れるかどうか判断して、残りは"git add"
$ git add .

...入れたくないファイル発見、"git restore"でUntracked状態にしておく
$ git restore --staged test.js

...次は".gitignore"を開いて書く、保存したら".gitignore"がModified状態になった
$ git commit -am  # 無視したいファイル除いてすべてTracked状態だから-amで直接コミットする

...
$ git log  # 履歴を見たら、確認したいことがあるから過去のバージョンSHA-1をコピーしてqキーで出る
$ git checkout バージョンSHA-1  # 7桁まで入力してもよい（CLIでもGUIでも過去バージョンの様子が確認できた。）

...確認作業が終わって
$ git checkout ブランチ名  # ブランチ最新バージョンに戻る
```
"**git checkout**”で過去のバージョンに切り替えて、作業が終わって別のブランチを作ってコミットするのもよくあるんですが、今回は簡単かつシンプルな実践をやってみました。これからGitとGitHub、Gitflowとbranchの関係をまとめていきたいと思います。

# 参考資料
[github/gitignore: A collection of .gitignore templates](https://github.com/github/gitignore)
[.gitignore の書き方 - Qiita](https://qiita.com/inabe49/items/16ee3d9d1ce68daa9fff)
[コミットメッセージについてのガイド - ITnews](https://itnews.org/news_contents/a-guide-on-commit-messages)
[初めてのcommit](https://alligator.io/workflow/git-commit-and-collab/#:~:text=root%2Dcommit%20means%20that%20this,new%20commit's%20unique%20ID%20number.)
[git commit を取り消して元に戻す方法、徹底まとめ | WWWクリエイターズ](https://www-creators.com/archives/1116#1_git_commit)
[忘れやすい人のための git diff チートシート - Qiita](https://qiita.com/shibukk/items/8c9362a5bd399b9c56be)