Git commands

#Git 自分用コマンド総まとめ

参考にした本：[progit](https://git-scm.com/book/en/v2)

Need to know:
- vim commands　
- Linux commands

---

### 0. Terminology 
- **Committed** means that the date is safely stored in the local database
- **Modified** means that file is changed but have not committed it to my database yet.
- **Staged** means that I have marked a modified file in its current version to go into my next commit snapshot.
  
More details: [Difference between untracked, unstaged and staged changes](https://howtogit.net/concepts/types-of-changes.html)

- Git バージョンチェック

```bash

git --version
```


###1. コミットの位置:

 1. **origin**: a term for the remote repository 

 2. **master**: a local branch 
        - ローカルリポジトリのブランチ「master」の位置
 
 3. **origin/master** 
        - リモートリポジトリ「origin」のブランチ「master」の位置。
        - Remote branch (which is a local copy of the branch named *master* on the remote repository named origin)
        
 4.  **origin/HEAD**
        - リモートリポジトリ「origin」をクローンした時にダウンロードされるコミットの位置

### 2. Git commands

####Initializing a Repository
- 新規ローカルリポジトリの作成

```bash

mkdir sample
cd sample
```
で、適当に好きなところに空っぽのディレクトリを作り、

```
git init
```
Gitリポジトリに設定。

- 既にあるプロジェクトからレポ作成

```bash

cd /そのプロジェクトのdirectory
git init #新しく作成したディレクトリをGitリポジトリに設定

# directoryにぽいぽい入れたいファイルらを追加する。working tree のみ存在しているので次にインデックスに追加する。

git add <FILE-NAME> #インデックスに登録したいファイルを登録
git add . #もしくはパラメータに「.」を指定すると、すべてのファイルをインデックスに登録できる

git commit -m 'comment'
```
### Adding to remote repository 
作ったローカルレポジトリをgithub上でリモートリポジトリに追加

```bash
# 新規のGitHubリポジトリのURLをコピーし、リモートブランチoriginとして設定
git remote add origin <URL>

# ローカルのファイルをリモート上にアップロード
git push -u origin master
```

#### Cloning an Existing Repository
既にあるリモートリポジトリを複製する。

```bash

git clone <url> <保存先のdirectory>
```

githubでの新規repo作りかた:
 [新規にリポジトリ作りたいときのgithubとコマンド操作例](http://tweeeety.hateblo.jp/entry/2014/11/19/235517)
#### Check status
- Gitの管理下にあるディレクトリの、ワークツリーとインデックスの状態を確認

```bash

git status
```
- ```git status```のディスプレイを簡潔にしたい場合

```bash
git status -s
git status --short
```
![Screen Shot 2018-08-29 at 6.11.16 PM.png](https://qiita-image-store.s3.amazonaws.com/0/136608/7487cfb5-9b1f-1844-8ddb-4c8b5656cc93.png)

>
?? = インデックスにないファイル
M = Modified file, つまりファイル内容がなんらか変更された
A = 既にステージングされているファイル（インデックスに既にある）

There are two columns to the output:
    - the left- hand column indicates the status of the staging area and 
    - the right-hand column indicates the status of the working tree 

上記の場合、　README は内容が変更されたけれども、インデックスにはなく、ステージングされていない。
lib/simplegit.rb は、ファイルが変更され、なおかつ既にインデックス内にある状態。
Rakefile は最初の変更がステージングされた後に変更をまたしたので、最後の変更はステージングされていない。

#### Check Difference
ファイルの差異を確認。

•　どのファイルのどの箇所を編集したのか確認したい場合

```bash
git diff # index と　working tree　の差分を表示
```
```bash
git diff --staged # 既にステージされたファイルの変更のみ表示
git diff --cached # index(staging area)と HEAD(repository) の差分
```

```bash
git diff HEAD # Working tree と　HEAD(repository) の差分
```

さらに詳しい```git diff```の使い方：[よく使う git diff コマンド](https://qiita.com/hide/items/17b970c485e803cbce08)
Youtube video: [git diff Revised](https://youtu.be/qdR5B6Pl-ks)
[gitの変更/差分確認方法](https://www.wize-net.co.jp/techlog/git/28#localdiff)

#### 新しくファイルを作ってそれをローカルレポに追加するには

echoや

```bash
echo 'sample' > SAMPLE.txt  
```
touchコマンドでまず新規ファイルを作成。

```bash

touch SAMPLE.txt
```
- ファイルをインデックスに追加する、

```bash

git add SAMPLE.txt
```
*もしファイルが既に```git add```でインデックスにある状態でそのファイル内容を変更した場合、もう一回```git add```で最終更新したバージョンのファイルを```git add```しなくてはならない。

- addしたファイルをコミットする

```bash

git commit -m "comment"
```

- リポジトリの変更履歴を確認

```bash
git log
git log -oneline # 一行で表示
git log -2 #最新の二つの履歴までのみ表示
git log --since=2.weeks # 今日から二週間前の履歴まで表示
```
自分でコミット履歴表示をカスタマイズ

```bash
git log --pretty=format:"<options>..."
例：
git log --pretty=format:"%h = %an, %ar: %s"
```

すると、
![Screen Shot 2018-08-31 at 9.37.08 AM.png](https://qiita-image-store.s3.amazonaws.com/0/136608/71345f71-ff51-c5ff-8e70-10e9aec4e77d.png)
と表示される。

**--pretty=format オプション一覧**
![Screen Shot 2018-08-31 at 9.35.24 AM.png](https://qiita-image-store.s3.amazonaws.com/0/136608/a83527d1-4086-836d-323d-6e6a888a4251.png)
progit から抜粋。


その他の```git log```オプション：
[git logを見やすくしたい](https://qiita.com/forest1/items/82ac22596fbe65187a8b)
[git log よく使うオプション一覧](https://flashbuilder-job.com/github/98.html)
#### Ignoring Files
- gitに入れたくないファイルや、表示したくないファイルや意図的に追跡対象から外したい（無視したい）ファイルを設定
- .gitignoreが無視するファイルは、まだインデックスに登録されていないものだけ

```bash
cat .gitignore # git ignore ファイルを作成し、次に行から追跡したくないファイルを入れる。
#例
*.[oa] # .o や、.a　で終わるファイル（object or archive file)

EXAMPLE.txt # EXAMPLE.txt は対象外

*.html # 全てのhtmlファイル

!sample.html # ! を使うと、gitの管理対象となる。すなわちsample.htmlは管理対象だがその他のhtmlは対象外

example/ # ディレクトリ名を指定した場合、対象のディレクトリはgitの管理外に。ディレクトリ名は、最後に / を付けて指定。

/TODO # .gitignoreと同ディレクトリにあるTODOのみを無視したい場合は、/TODOと書く。

doc/*.txt # doc/notes.txt は無視されるが、　doc/server/arch.txt　は無視されない。
```
**ワイルドカード**：
- An asterisk (\*) matches zero or more characters
- [abc] matches any character inside the brackets (in this case a, b, or c)
-  a question mark (?) matches a single character
-  brackets enclosing characters separated by a hyphen ([0- 9]) matches any character between them (in this case 0 through 9). 
-  two asterisks to match nested directories
    - EX: a/**/z　だと a/z, a/b/z, a/b/c/z　が対象。

さらに詳しい```git ignore```の使い方はこちらを参考：[[Git] .gitignoreの仕様詳解](https://qiita.com/anqooqie/items/110957797b3d5280c44f)

```git status```で.gitignoreファイルに入っているファイルたちがgitの管理外に置かれているのを確認できる。（.gitignore　は管理対象）

#### Committing your changes 

```bash
git commit
git commit -v # どこをmodified したのか見ながらコメントが残せる。

# vim エディタが開くのでコメントを書き終えたら　esc + :wq でセーブ
```

```bash

git commit -m "comment" #コメントをcommit コマンドと同時に書ける
```
**Warning**:　local repository にcommitされるのはstagedされたファイルのみなので、既にadd したファイルを後でまた内容を編集した場合、そのファイルをまた```git add```しなければ、最終変更した内容は　```git commit``` した時に　local repository　に反映されないので注意。

**TIP**: commitした後毎回　git status でcommitできたか確認する。


#### Skipping the Staging Area
いちいち ```git add```でファイルらをインデックスに入れるの面倒な時。

```bash
# git add をすっ飛ばしてまとめて直でgit commit してくれる。
git commit -a
git commit -a -m "comment"
```
例：
![Screen Shot 2018-08-30 at 8.14.45 PM.png](https://qiita-image-store.s3.amazonaws.com/0/136608/a5bcf1ce-4819-143c-6911-a3080463f31a.png)
- 既にlocal repositoryに入れてある（すなわちtracked--追跡対象に--されている）ファイル ex2.py & ex3.rtfファイルの中身を変更して　```git commit -a ``` で一気にaddをすっ飛ばしてcommitできる。

**Warning**:オンリー追跡対象のファイルのみに適用！！だから新しく入れたファイルは```git add```で追跡対象にしなきゃいけないよ

#### Removing files
- trackedファイルをGitの対象から外す

**Case 1: tracked file をgitからも自分のコンピューターからも削除したい！**

```bash
git rm <file name>
```
```git status```で、　```deleted: <file name>``` を確認。 ```git commit```で削除。

例:

```bash
git rm log/\*.log # log/ ディレクトリ内にある　.log で終わるファイルを削除
```


**Case 2: tracked file をgitの追跡対象から外したいけど、削除じゃなくて手元に残しておきたい。(間違えてstageしてしまったファイルや、.gitignoreに追加したいファイルなど）**

```bash

git rm --cached <File Name>
```

**Case: やっぱ削除やめやめってしたいとき** 
基本：

```bash
git reset --hard HEAD
```
でも、ケースによるので深くはここで説明しない。

詳しくはこちらを参考（事例ごとにどうやるのかが書かれています）: [Git で変更を取り消して、元に戻す方法 (事例別まとめ)](http://www-creators.com/archives/1290)


その他：
- [git rm したファイルを元に戻す方法](https://qiita.com/shungok/items/82a06b1c4c93922a8622)
- [GITの対象から外したいけど、ファイル自体は残しておきたい](https://tech.nosuz.jp/2017/05/stop-tracking-files-on-git/)
- [さらに詳しいgit rm](https://www.atlassian.com/git/tutorials/undoing-changes/git-rm)

#### Moving files
-ファイルの移動

- ファイル名を変更

```bash
git mv file_from file_to 
```
```git mv```じゃなくて普通に```mv```コマンドを売ってしまった場合：
[Git で管理しているファイルのリネームを git mv でなく mv してしまったときにどうなるのか調べてみた](https://qiita.com/yynozk/items/7705844c5e255b8fa3ae)

- ファイルの移動

```bash
git mv <移動したいファイル名> <移動先ディレクトリ>

# 忘れずに移動したよ！ってcommitする。
```

#### Undoing Things
-変更を取り消して元に戻したい時

**Case 1: 直前コミットを上書きする**
- コミットした後に、最後にコミットしたコメントを編集したい時や、入れ忘れたファイルを入れたい場合。

```bash
git commit --amend
```
- 変更したファイルを追加したい時

```bash
Example:
git commit -m '最初のコミット'　#例えばこのコミットにファイルを追加し忘れたら
git add 入れ忘れたファイル
git commit --amend 
# 一つのコミットとして表示される。
```

**Case 2: Unstaging a Staged File**
インデックスに追加してしまったファイルを元に戻す。
- ```git add*```でインデックスに入れたファイルのうち一つをインデックスから外したい場合

```bash
git reset HEAD <file_name>
```

- 編集したファイルの内容を最後にコミットした時の内容に戻したい時

```bash
git checkout <file_name> #注：working tree（unstaged area)内にある時のみ。
```

もっと詳しく：
[git commit を取り消して元に戻す方法、徹底まとめ](http://www-creators.com/archives/1116)
[Git で変更を取り消して、元に戻す方法 (事例別まとめ)](http://www-creators.com/archives/1290)
[git add の取り消し方法と、関連コマンドまとめ](http://www-creators.com/archives/1282)

#### Fetching and Pulling from Your Remotes
- リモート内のファイルらをfetchでローカルに入れる

```bash
git fetch <REMOTE>

# EXAMPLE:
git fetch origin #fetchでは、リモートからのファイルは現在のローカルのファイルとmergeしない
```

fetchについて詳しく：[more about fetch](https://www.atlassian.com/git/tutorials/syncing/git-fetch)

pull とfetch の違い：[difference between fetch and pull](https://www.git-tower.com/learn/git/faq/difference-between-git-fetch-git-pull)

- Pullでリモートから fetch + mergeする。

```bash
git pull #remote から全てのブランチがpull
```

```bash
git pull <REMOTE> <local Branch>

# EXAMPLE
git pull origin master # remote origin から master ブランチのみ　pull
```
More about pull:
[git pull](https://www.atlassian.com/git/tutorials/syncing/git-pull)

### Pushing to your remotes
- ローカルからリモートに上げる

```bash
git push <remote> <branch>

# Exmample
git push origin master　# local の master ブランチ を　origin remote に push
```

```git push```だけでも、今いるブランチのみをpushする。
```git push --all```だと全てのブランチをpushする。

- リモート情報をみる

```bash
git remote  show <REMOTE>
```
- リモートの追加

```bash
git remote add <REMOTE> <URL> # REMOTE名はoriginが既にある場合、違うのを選ぶ
```
- リモート名の変更

```bash
git remote rename <NEW_REMOTE_NAME> <ORIGINAL_REMOTE_NAME>
git remote #ディレクトリ内のリモートの一覧
```
- リモートをプロジェクトから外したい

```bash
git remote remove <REMOTE>
```

### Tagging 
-タグ付け。コミットIDをヒトに理解しやすくするための別名
詳しくは：[GitのTagの使い方](https://numb86-tech.hatenablog.com/entry/2017/03/26/123507)
- 二種類のタグ：　lightweight(軽量) と annotated(注釈付き)
    - lightweight: 名前を付けられる
    - annotated: 名前を付けられる、コメントを付けられる、署名を付けられる
    
使い用途：
    - リリースタグにはannotated tag を使ってコメントや署名を追加。
    - lightweight tagはローカルで一時的に使用する使い捨てなどに使用
 

```bash
git tag # タグ一覧
git show # タグ情報
```

- Annotated tagの追加

```bash
git tag -a <tag_name> -m "comment"

git tag -a <tag_name> <commit_ID> #過去のコミットにタグをつけたい場合はcommit ID をタグ名の後に追加する。
```
- Lightweight tagの追加

```bash
git tag <tag_name>
```
- Tag を　リモートにシェア

注：```git push```のみではタグはプッシュされないので、別でタグを上げる

```bash
git push <REMOTE> <TAG_NAME> # リモート名とシェアしたいタグ名を載せる
git push <REMOTE> --tags # 複数のtagをリモートにシェア
```

- Checking out Tags

```bash
git checkout <tag名> # tagが指しているファイルを確認

#　repository が　'detached HEAD'状態になる

# もしそこからファイルを編集してcommitしたいなら、
# -b option で新しいブランチを作ってcommitする。
git checkout -b <new_branch> <tag> 
```

###Git Aliases
- いちいち```git commit```などと書くのが面倒な時、ショートカットを設定

```bash
# よく使うコマンドたちのショートカットを作成
git config --global alias.co checkout #git checkout == git co
git config --global alias.ci commit #git commit == git ci
git config --global alias.st　status #git st == git status

# 自分でコマンドを設定
git config --global alias.last 'log -1 HEAD' #git last で最後のコミットをみる
```

もっと詳しく：[gitで便利なエイリアス達](https://qiita.com/peccul/items/90dd469e2f72babbc106)

####GIT BRANCHING
- ブランチ,マージについては次の記事でまとめます。


Git Useful Learning Guide: 
[Resources to learn Git](https://try.github.io/)
[GitHowTo](https://githowto.com/)
[図解Git](https://marklodato.github.io/visual-git-guide/index-ja.html)
[Githubによるintro to github](https://services.github.com/on-demand/)

感想：
SourceTree でGUIでの操作に慣れると、ど忘れによるコマンド打ち間違えとか多くて困る。

解決したい疑問：
- git pull, git fetchらで、remote や　branch名なしだと、全てのbranches がlocal repoにアップデートされるのか？