【随時更新】Git コマンドのまとめ

## はじめに

Git コマンドのまとめです。基本的に [Pro Git](https://git-scm.com/book/ja/v2) や、[GitHub実践入門 ~Pull Requestによる開発の変革](https://amzn.to/3gq66pq) をベースに作成しています。

## コマンド

### git init - リポジトリ初期化

```sh
$ mkdir git
$ cd git/
$ git init
Initialized empty Git repository in /Users/XXXXXXX/projects/git/.git/
$ ls .git/
HEAD		description	info		refs
config		hooks		objects
```

### git config

- git config
	- /etc/gitconfig ファイル: システム上の全てのユーザーと全てのリポジトリに対する設定値を保持
	- ~/.gitconfig か ~/.config/git/config ファイル: 特定のユーザーに対する設定値を保持
		- --global オプションを指定することで、Gitに、明確にこのファイルに読み書きを行なわせることができる
	- 現在使っているリポジトリのGitディレクトリにある`config`ファイル(`.git/config`のことです): 特定の 単一リポジトリに対する設定

```sh
$ git config --global user.name "xxxxxxx"
$ git config --global user.email xxxxxxx@xxxxx.xxx
$ git config --global core.editor vim
```

### git status - リポジトリ の状態を確認

- master ブランチにいて、コミット対象が存在しない

```sh
$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)
```

- master ブランチにて、ファイルは存在するが追跡されていない
   - ワーキングツリーでファイルを作成しただけでは、Gitリポジトリのバージョン管理の対象としてファイルは登録されていない

```sh
$ ls
$ touch README.md
$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	README.md

nothing added to commit but untracked files present (use "git add" to track)
```

### git add

- いくつかの機能がある
   - 新しいファイルの追跡開始
   - ステージ領域へファイルを追加
      - コマンドを実行した時点の状態のファイルをステージする
   - マージ時に衝突が発生したファイルに対する「解決済み」マーク付け

- ファイルを Gitリポジトリの管理対象とするために`git add`コマンドを利用してステージ領域と呼ばれる場所にファイルを登録
   - `Changes to be committed:`以下がステージ領域にされているファイル

```sh
$ git add README.md
$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   README.md
```

### git diff - 変更したけどまだステージしていない変更を確認

```sh
$ git diff
```

- `--staged`, `--cached`: ステージされている変更と直近のコミットの内容を比較する場合

```sh
$ git diff --staged
```

- `--check` : スペースの次にタブ、および末尾スペースがあったときに警告メッセージを出す

```sh
$ git diff --check
```

- tool で確認する

```sh
$ git difftool
```

### git commit - リポジトリの歴史を記録

- `git commit`コマンドはステージ領域に登録されている時点のファイル群を実際にリポジトリの歴史として記録する

```sh
$ git commit -m "First Commit"
[master (root-commit) 9b7066c] First Commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md
```

### git rm - ファイルの削除をステージする

- ファイルの削除をステージする

```sh
$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage) deleted: PROJECTS.md
```

普通に rm すると、not updated” (つまり ステージされていない) 欄に表示される

```sh
$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'. Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: PROJECTS.md
no changes added to commit (use "git add" and/or "git commit -a")
```

- ファイル自体は作業ツリーに残しつ つステージングエリアからの削除だけを行う

```sh
$ git rm --cached README
```

### git mv - ファイル名を変更してステージする

```sh
$ git mv README.md README
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage) renamed: README.md -> README
```

### git log - コミットログを確認

- リポジトリにコミットされたログを確認

```sh
$ git log
commit 6e8a1e7b11668f66c60b45c5ce955ccb165cf761 (HEAD -> master)
Author: xxxxxxxxx <xxxxxxxxx@xxxxxx.xxx>
Date:   Mon May 11 08:06:14 2020 +0900
    test
```

- `--graph`でブランチの分岐を視覚的に表現する

```sh
$ git log --graph
*   commit b1ef120598526f44d60c618edfcb29532905aaed (HEAD -> master)
|\  Merge: 6e8a1e7 30ae9ad
| | Author: xxxxxxxxx <xxxxxxxxx@xxxxxxxxx.xxx>
| | Date:   Tue May 12 07:53:47 2020 +0900
| |
| |     Merge branch 'test'
| |
| * commit 30ae9adf05acda9f9be221eb61104daa89ea8708 (test)
|/  Author: xxxxxxxxx <xxxxxxxxx@xxxxxxxxx.xxx>
|   Date:   Tue May 12 07:44:35 2020 +0900
|
|       add test to test
|
* commit 6e8a1e7b11668f66c60b45c5ce955ccb165cf761
| Author: xxxxxxxxx <xxxxxxxxx@xxxxxxxxx.xxx>
| Date:   Mon May 11 08:06:14 2020 +0900
|
|     test
|
```

- ` --stat`：各コミットエントリに続けて変更されたファイルの一覧と変更されたフ ァイルの数、追加・削除された行数が表示

```sh
 $ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700
      changed the version number
Rakefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 16:40:33 2008 -0700
      removed unnecessary test
lib/simplegit.rb | 5 -----
1 file changed, 5 deletions(-)
commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon <schacon@gee-mail.com> Date: Sat Mar 15 10:31:28 2008 -0700
first commit
README | 6 ++++++
Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+)
```

- `--pretty` ： 独自のログ出力フォーマットを指定

```sh
 $ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number 085bb3b - Scott Chacon, 6 years ago : removed unnecessary test a11bef0 - Scott Chacon, 6 years ago : first commit
```

- `--since` ： 時間制限のオプション

```sh
$ git log --since=2.weeks
```

- `-S`：任意の文字列を引数にでき、その文字列が追加・削除されたコミットのみを抜き出す

```sh
$ git log -Sfunction_name
```

### git remote - リモート Git リポジトリにアクセスしやすいような名前をつけて追加

- 新しいリモート Git リポジトリにアクセスしやすいような名前をつけて追加する
  - どういう時に使うのかはわからん

```sh
$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)
```

### git tag - 歴史上の重要なポイントに印をつける

- 既存のタグの一覧を表示

```sh
$ git tag
v0.1
v1.3
```

- タグの作成
  - タグには軽量 (lightweight) 版と注釈付き (annotated) 版の二通りがある

- 現在のHEADが指しているコミットに注釈付きタグを付与する

```sh
$ git tag -a v1.4 -m "my version 1.4"
$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc> Date: Sat May 3 20:19:12 2014 -0700
my version 1.4
commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700
      changed the version number
```

- 現在のHEADが指しているコミットに軽量タグを付与する

```sh
$ git tag v1.4-lw $ git tag
v0.1
v1.3
v1.4 v1.4-lw v1.5
$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon <schacon@gee-mail.com> Date: Mon Mar 17 21:52:11 2008 -0700
      changed the version number
```

- 後から tag を付与する

```sh
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support 0d52aaab4479697da7686c15f77a3d64d9165190 one more thing 6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment' 0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function 4682c3261057305bdd616e23b64b0857d832627b added a todo file 166ae0c4d3f420721acbb115cc33848dfcc2121a started write support 9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
$ git tag -a v1.2 9fceb02
```

- tag をリモートに push
  - デフォルトでは、git push コマンドはタグ情報をリモートに送らないため、タグを作ったら、タグをリモートサーバーにプッシュするよう明示する必要がある
  - git push origin [tagname]

```sh
$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done. Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new tag] v1.5 -> v1.5
```


### git checkout - ブランチの切り替え

- オプションなし
    - 作業ディレクトリやステージングエリアに未コミットの変更が残っている場合、それがもしチェックアウト先のブランチと衝突する内容ならブランチの切り替えはできない

```sh
$ git branch
* master
$ git branch new_branch
$ git branch
* master
  new_branch
$ git checkout new_branch
Switched to branch 'new_branch'
```


- `-b` : リモート分析ブランチをもとにローカルブランチを作成しつつ切り替える

```sh
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix'
```

### git branch - ブランチを表示、作成、削除

- オプションなし

```sh
$ git branch
* master
  dev
```

- `-r` : リモートブランチの状態を確認

```sh
$ git branch -r
  origin/HEAD -> origin/main
  origin/main
  origin/master
```

- `-d` : ブランチを削除

```sh
$ git branch -d test
```

- `-vv` : ブランチ名 コミット番号 [追跡ブランチ名] コミットメッセージ を確認



```shell
$ git branch -vv
   iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets
   master 1ae2a45 [origin/master] deploying index fix
 * serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
   testing   5ea463a trying something new
```

- iss53 ブランチが origin/iss53 を追跡していて、リモートより二つぶん「先行している (ahead)」
- master ブランチは origin/master を追跡しており、最新の状態である
- serverfix ブランチは teamone サーバー上の server-fix-good ブランチを追跡しており、 三つ先行していると同時に一つ遅れている
- testing ブランチは、リモートブランチを追跡していない



### git merge - ブランチをマージ

- `--no-ff`でマージコミットメッセージを記入するためのエディタが立ち上がる

```sh
$ git checkout master
Switched to branch 'master'* master
$ git merge --no-ff test
Merge made by the 'recursive' strategy.
 test | 4 ++++
 1 file changed, 4 insertions(+)
```

- `--merged` or `--no-merged` : 現在作業中のブランチに マージ済みのもの (あるいはそうでないもの) だけを表示

```sh
$ git branch
    iss53
  * master
    testing
$ git branch --merged
  iss53
* master
```

このリストにあがって いるブランチのうち先頭に`*`がついていないものは、通常は `git branch -d` で削除してしまって問題ない

```sh
$ git branch --no-merged
testing
```

- `--abort` : マージの中止

```sh
$ git merge whitespace
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Automatic merge failed; fix conflicts and then commit the result.
$ git status -sb
## master
UU hello.rb
$ git merge --abort
$ git status -sb
## master
```

### git rebase - 一方のブランチにコミットされたすべての変更をもう一方のブランチで再現

リモートブランチ上での自分のコミットを一直線にするために使用する

```sh
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it... Applying: added staged command
```

<img width="577" alt="スクリーンショット 2020-08-06 21.09.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/28cd061f-60b7-2c29-ac0c-23632de4d366.png">

master ブランチに戻って fast-forward merge できる

```sh
$ git checkout master
$ git merge experiment
```
<img width="572" alt="スクリーンショット 2020-08-06 21.11.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/5a1496a7-c458-b60c-0a41-e43a3a07e46b.png">

### git reset - 現在のHEADを特定の状態にリセットする

- `--soft` : commit のみ取り消し
   - `HEAD^` : 直前の commit を表す

```sh
$ git reset --soft HEAD^
```

- `--mixed` : commit と add の取り消し

```sh
$ git reset --mixed HEAD^
```

- `--hard` : commit と add とワーキングツリーの状態の取り消し
   - ワーキングツリーを上書きするので、注意

```sh
$ git reset --hard HEAD^
```

### git reflog - リポジトリで行われた作業のログを確認

- `git log` だと今の状態から過去のログしか見れない

```sh
$ git reflog
734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd HEAD@{2}: commit: added some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD
```

### git rebase -i - 過去のコミットを改変する

- 最新のコミットを１つ前のコミットに含める
   - １つ前のコミットに間違えが見つかった時に、修正したコミットを使って改竄するイメージ

```sh
$ git rebase -i HEAD-2
```

### git remote add - リモートリポジトリを登録

- origin という識別子で`https://github.com/XXXXXXX/git-test.git`を指すようになる

```sh
$ git remote add origin https://github.com/XXXXXXX/git-test.git
$ cat .git/config
[remote "origin"]
	url = https://github.com/XXXXXXX/git-test.git
	fetch = +refs/heads/*:refs/remotes/origin/*
```

### git stash - 作業を隠す

ある作業が中途半端な状態になっているがブランチを切り替えてちょっとだけ別の作業をしたくなった時に、できればコミットせずにしておいて後でその状態から作業を再開したい場合に利用する

```sh
$ git status
  Changes to be committed:
(use "git reset HEAD <file>..." to unstage) modified: index.html
Changes not staged for commit:
(use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working
directory)
modified: lib/simplegit.rb
```
追跡しているファイルのうち変更されたもの、そしてステージされた変更を受け取って未完了の作業をスタックに格納し、あとで好きなときに再度それを適用できるようにする

```sh
$ git stash
  Saved working directory and index state \
"WIP on master: 049d078 added the index file" HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
```

作業ディレクトリはきれいな状態になった

```sh
$ git status
  # On branch master
  nothing to commit, working directory clean
```

- `list` : スタックに格納した内容の確認

```sh
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
```

- `apply` : 隠したファイルを元に戻す
   - 変更を隠したときと同じブランチに書き戻す
   - 以前にステージしていたファイルはステージされていない
      - `--index` オプションをつけると変更のステージ処理も再適用する

```sh
$ git stash apply
  On branch master
  Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: index.html modified: lib/simplegit.rb
no changes added to commit (use "git add" and/or "git commit -a")
```

### git push - リモートリポジトリを操作

- `-u`: upstream を設定
   - 初めてブランチを Push するときに`-u`オプションをつけることを推奨
   - 現在のブランチの内容を送信
     - git push [remote-name] [branch-name]

```sh
$ git push -u origin master
```

- `--delete` : リモートブランチの削除

```sh
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
- [deleted] serverfix
```

### git clone - リモートリポジトリを取得

- git clone 直後は master ブランチにいる

```sh
$ git clone https://github.com/XXXXXXX/git-test.git
Cloning into 'git-test'...
remote: Enumerating objects: 21, done.
remote: Counting objects: 100% (21/21), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 21 (delta 5), reused 19 (delta 3), pack-reused 0
Unpacking objects: 100% (21/21), done.
$ cd git-test/
$ git branch
* master
```

### git branch - 現在のブランチを表示

- `-a` オプションでリモートリポジトリのブランチも表示

```sh
$ git branch
* master
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/test
```

### リモートリポジトリのブランチをチェックアウト

```sh
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/test
$ git checkout -b test origin/test
Branch rebase set up to track remote branch rebase from origin.
Switched to a new branch 'test'
$ git branch
  master
* test
```

### git fetch - リモートリポジトリの最新の履歴の取得だけを行う

- リモートリポジトリの最新の履歴の取得だけを行う
  - remote-name とは `git remote -v` で表示される名前でデフォルトは `origin`
  - git branch -r の前に

```sh
$ git fetch [remote-name]
```

- `-p, -prune`でリモートに存在しないリモート追跡ブランチを削除

```sh
$ git fetch -p
```

リモートリポジトリの



### git pull - 

- リモートリポジトリの内容を取得し、マージする
  - git fetch + merge

```sh

```

- [Git 再入門: 引数がない git pull のデフォルトの挙動 (アップストリーム, トラッキングブランチについて)](https://www.yunabe.jp/docs/relearning_git_pull_default.html)



### pull request の流れ

- fork する
- fork したリポジトリを clone する
- clone したリポジトリでトピックブランチを作成
- コードを修正
- git add, commit
- 元のリポジトリに pull request を送る

### フロー

![スクリーンショット 2020-05-09 9 05 30](https://user-images.githubusercontent.com/20186020/81458244-64e45000-91d4-11ea-87cd-dd01599efbd2.png)

- [2.2 Git の基本 - 変更内容のリポジトリへの記録](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E5%9F%BA%E6%9C%AC-%E5%A4%89%E6%9B%B4%E5%86%85%E5%AE%B9%E3%81%AE%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%B8%E3%81%AE%E8%A8%98%E9%8C%B2)

### git flow

- master ブランチは常にデプロイできる状態とする
- 新しい作業をするときは、masterブランチから記述的な名前のブランチを作成する
  - 記述的とはブランチの特性を明確に著した
- 同名のブランチを GitHub のリポジトリに定期的に push する
- Pull Request を送り、レビューをしてもらう
- master ブランチにマージし、直ちにデプロイする

### コミットのやり直し

- ステージングエリアの内容をコミットに使用する
  - 直近のコミット以降に何も変更をし ていない場合 (たとえば、コミットの直後にこのコマンドを実行したような場合)、 スナップショットの内容 はまったく同じでありコミットメッセージを変更することになる
- 最終的にできあがるのはひとつのコミット。二番目のコミットが、最初のコミットの結果を上書きする

```sh
$ git commit --amend
```

### コンフリクト時

```sh
$ git pull
error: Pulling is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
$ vim conflict_file
$ git add conflict_file
$ git commit -m "resolve conflict"
```

## 利用すると便利なリンク

### .gitignore

- [Python.gitignore](https://github.com/github/gitignore/blob/master/Python.gitignore)
    - Python でよく使う .gitignore 例


### git complition

- [「Git補完をしらない」「git statusを1日100回は使う」そんなあなたに朗報【git-completionとgit-prompt】](https://qiita.com/varmil/items/9b0aeafa85975474e9b6)
  - gitコマンドの補完スクリプト
  - プロンプトに各種追加情報を表示可能にするスクリプト

### git alias

- git コマンドの別名をつけて簡略化する

```sh
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
```

## Git 用語

- リポジトリ
  - ファイルやディレクトリの状態を記録する場所で、保存された状態は、内容の変更履歴として格納される
- リポジトリデータ
  - `.git` ディレクトリに存在するワークツリー以下を管理するファイルたち
- ワークツリー(ワーキングツリー)
  - `git init`コマンドを実行したディレクトリ以下のこと 
- コミット
  - ワークツリーにある全てのファイルのその時点の状態を記録すること
- HEAD
  - 作業しているローカルブランチへのポインタ
- ステージ(インデックス)エリア
  - コミットをする前の一時領域
- トピックブランチ
  - １つのトピックに集中して他の作業は一切行わないブランチ
- 上流ブランチ
  - あるローカルブランチが、履歴を追跡するように設定したリモートブランチの事