新しい開発をする時に迷わずGitを準備するための覚書

# はじめに
新しい開発を行う時に手が止まらないようGitの設定や手順を残しておきます。
なお、本記事は以下のUdemy講座を元にした覚書です。
[米国AI開発者がやさしく教えるGit入門講座](https://www.udemy.com/share/1046EOAEASdltXRH0F/)

# 前提
- 手元のPCにGitインストールされていること
- GitHubにアカウントがあること

# 記事中の構成
実行結果をそのまま記載しているため、適宜以下は変更してください。

- Gitユーザー名:c3drive
- リポジトリ名：my-git-practice / git-practice
- 作業ブランチ名：update-readme / new-feature / conflict など

# git構成覚書
【ワーキングディレクトリ】…作業をしているところ
↓　git add　　　↑　git restore
【ステージングエリア】…addされているところ
↓　git commit　 ↑　git restore --staged
【リポジトリ/作業用ブランチ】※

--リモートリポジトリがある場合--
↓　git push　　　↑　git pull
【リモートリポジトリ/作業用ブランチ】
↓ pull request
【リモートorfork元リポジトリ/mainブランチ】

※ローカルブランチしかない場合、このタイミングでローカルでmainにマージ（git merge）する。

# SSHアクセス設定（PCを変えた時）
GitHubでパスワード認証は2021/08/13に使えなくなります（[参考](https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/)）
二段階認証など別の認証をしている場合、この手順は不要です。

### SSHキー作成

```bash:
# SSHキーを作成（アルゴリズムはed25519）
# パスフレーズを聞かれる（指定なければそのままエンター）
$ sh-keygen -t ed25519 -C "｛メールアドレス｝"

# ~/.ssh配下に公開鍵と秘密鍵が作成される
$ ls -l ~/.ssh
-rw-------  1 yukokanai  staff   419  2 16 12:56 id_ed25519
-rw-r--r--  1 yukokanai  staff   110  2 16 12:56 id_ed25519.pub

# ssh-agentを起動
$ ebal "$(ssh-agent -s)"

# ~/.ssh/configファイルを編集する（編集内容は後述）
$ subl ~./ssh/config

# SSHキーをssh-agentに登録する
$ ssh-add -K ~/.ssh/id25519
```
```:~./ssh/config
Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519
```
### 作成したSSHキーをGitHubに登録

```bash
# 公開鍵（.pubがついている方）をクリップボードにコピー
$ pbcopy < ~/.ssh/id25519.pub
```
GitHubに移動して、必要情報を入力したら「Add SSH key」を押下

- URL(※)：https://github.com/settings/ssh/new
- Title：（任意）
- Key：（クリップボードにコピーした公開鍵の中身）

※[Account] - [settings] - [SSH and GPG keys] - [New SSH key]でも可能 

#ユーザーの設定（global）

```bash:
$ git config --global user.name "｛ユーザー名｝"
$ git config --global user.email "｛メールアドレス｝"
```
--globalをつけることで、当該ユーザーのシステム全体の設定となる。（~/.gitconfig）
--globalをつけないことで、実行したリポジトリ独自の設定となる。（.git/config）

# エディタの設定（global）
```bash:ここではsublを指定しています
$ which subl
/usr/local/bin/subl
$ git config --global core.editor "/usr/local/bin/subl -n -w"
```

# diff/mergeツールの設定（global）
```bash:ここではp4mergeを指定しています
$ ls /Applications/p4merge.app/Contents/MacOS/
p4merge

$ git config --global diff.tool p4merge
$ git config --global difftool.p4merge.path "/Applications/p4merge.app/Contents/MacOS/p4merge"
$ git config --global difftool.prompt false

$ git config --global merge.tool p4merge
$ git config --global mergetool.p4merge.path "/Applications/p4merge.app/Contents/MacOS/p4merge"
$ git config --global mergetool.prompt false
```

```bash:設定後の使い方
$ git diff // 通常のdiffコマンド
$ git difftool // p4mergeが起動
```

# GitHubにリモートリポジトリ作成

GitHubに移動して、必要情報を入力したら「Create repository」を押下

- URL：https://github.com/new
- Repository name：任意
- Description：任意
- Public/Private：特に理由がなければPublicを選択
- Initialise thie repository with ：特に理由がなければREADME .gitgnoreを選択

## fork
一からリモートリポジトリを作成するのではなく、別のアカウントの既存のリモートリポジトリを自分のリポジトリにコピーする方法です。
OSSに携わる場合などこのやり方をします。

やり方は、GitHubからforkしたいリモートリポジトリの画面のforkボタンを押下するだけです。
![スクリーンショット 2021-02-22 13.10.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/b22a1484-9b33-2c7c-44c1-4634622eee74.png)
自分のアカウントにforkしたリモートリポジトリが作成されていることを確認してください。

この後cloneしてローカルリポジトリで作業していくと思いますが、cloneするのはfork元ではなく、自分のリモートリポジトリですので注意してください。


# Gitリポジトリの作成
いくつか方法があります。

- [スクラッチから作成する](#スクラッチから作成する)
- [既存のディレクトリをGitリポジトリにする](#既存のディレクトリをGitリポジトリにする)
- [リモートリポジトリから作成する](#リモートリポジトリからcloneして作成)

### スクラッチから作成する

```bash:
$ cd ｛ローカルリポジトリを作成したいディレクトリ｝
$ git init ｛新しく作成したいリポジトリ名｝
```
Gitリポジトリになっているか確認

```bash
$ cd ｛リポジトリ名｝
$ ls -la
total 0
drwxr-xr-x  3 yukokanai  staff   96  2 22 11:48 .
drwxr-xr-x  4 yukokanai  staff  128  2 22 11:48 ..
drwxr-xr-x  9 yukokanai  staff  288  2 22 11:48 .git
```

### 既存のディレクトリをGitリポジトリにする

```bash:スクラッチの時と違い今いるディレクトリ名＝リポジトリ名になる
$ cd ｛ローカルリポジトリにしたいディレクトリ｝
$ git init 
```
Gitリポジトリになっているか確認

```bash
$ cd ｛リポジトリ名｝
$ ls -la
total 0
drwxr-xr-x  3 yukokanai  staff   96  2 22 11:48 .
drwxr-xr-x  4 yukokanai  staff  128  2 22 11:48 ..
drwxr-xr-x  9 yukokanai  staff  288  2 22 11:48 .git
```
`git status`で確認すると、そのディレクトリ配下に存在するファイルやディレクトリが全てワーキングディレクトリに表示されますので、既存のファイルやディレクトリは一括でステージングエリアに追加・コミットしましょう。

```bash:対象が多いので「.」で指定
$ git add .
$ git commit -m "initial commit"
```

##### リモートリポジトリの情報をセットしておく

GitHub上のリモートリポジトリのパス（SSH）をコピーする。

- URL：[リポジトリ] - [code] - [SSH] - クリップボードのマーク押下

```bash:
$ cd ｛リポジトリ名｝
$ git remote add origin ｛コピーしたリポジトリパス｝

// pullする時エラーになる場合
$ git pull --allow-unrelated-histories origin ｛branch名｝
```
### リモートリポジトリからcloneして作成

GitHub上のリモートリポジトリのパス（SSH）をコピーする。

- URL：[リポジトリ] - [code] - [SSH] - クリップボードのマーク押下

コピーしたパスでclone

```bash:
$ cd {ローカルリポジトリをcloneしたいディレクトリ}
$ git clone {コピーしたパス}
```
リモートリポジトリに紐づいているか確認

```bash
$ cd ｛リポジトリ名｝
$ git remote -v
origin	git@github.com:c3drive/my-git-practice.git (fetch)
origin	git@github.com:c3drive/my-git-practice.git (push)
```
##### fork元がある場合は、元のリポ情報をセットしておく。

GitHub上のfork元のリモートリポジトリのパス（SSH）をコピーする。

- URL：[リポジトリ] - [code] - [SSH] - クリップボードのマーク押下

```bash:upstreamはリファレンス名。なんでもいいがこれが一般的
$ cd ｛リポジトリ名｝
$ git remote add upstream ｛コピーしたfork元のリポジトリパス｝
$ git remote -v
origin	git@github.com:c3drive/git-practice.git (fetch)
origin	git@github.com:c3drive/git-practice.git (push)
upstream	git@github.com:D-S-Hub/git-practice.git (fetch)
upstream	git@github.com:D-S-Hub/git-practice.git (push)
```

# 作業用branchを作成し作業
##### まずは作業用branchを作成し切替

```bash
// 作成してから切り替える場合
$ git branch ｛branch名｝
$ git checkout ｛branch名｝

// checkoutにオプション指定することで作成と切替同時に実施することも可能
$ git checkout -b ｛branch名｝

// *が作成したブランチについていればOK
$ git branch
  main
* ｛branch名｝
```
##### 何らかの更新を行いステージングエリアへaddする

```bash
$ git status // add前にステータスを確認
On branch update-readme
Changes not staged for commit:
  　（略）
　　modified:  ｛更新をしたファイル｝

$ git add ｛更新をしたファイル｝

$ git status // add後にステータスを確認
On branch update-readme
Changes to be committed:
  　（略）
　　modified:  ｛更新をしたファイル｝
```
###### diff

```bash
$ git diff --staged HEAD // commit前にステージングエリアの状態とHEADを確認

// その他
$ git diff // ワーキングディレクトリとステージングエリアの状態を確認
$ git diff HEAD // ワーキングディレクトリとHEADの状態を確認
$ git diff -- {ファイル名} // {ファイル名}のみの状態を確認
$ git diff {コミットID1} {コミットID2} // {コミットID1}と{コミットID2}の状態を確認
$ git diff {branch名1} {branch名2} // HEAD^(HEADの親）とHEADの状態を確認
$ git diff {branch名1} {branch名2} // {branch名1}と{branch名2}の状態を確認
```

##### コミット

```bash
$ git commit -m "｛コメント｝"
[update-readme 8d3845b] update README
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git status // commit後にステータスを確認
On branch update-readme
nothing to commit, working tree clean
```
##### ファイル名の変更

```bash:addせずともmvだけでステージングエリアに入る
$ git mv ｛変更前ファイル名｝ ｛変更後ファイル名｝
$ git status
Changes to be committed:
	renamed:    newfile.txt -> namechanged.txt
```
基本は、`git mv`で管理するのが良いと思いますが、`mv`してしまった場合でも以下のようにすることでリネームと見做してくれる。

```bash:gitコマンドではないmvをしてしまっても一緒にaddするとリネームと見做される
$ mv ｛変更前ファイル名｝ ｛変更後ファイル名｝
$ git status
Changes not staged for commit:
	deleted:    namechanged.txt
Untracked files:
	namechanged2.txt
$ git add -A
$ git status
Changes to be committed:
	renamed:    namechanged.txt -> namechanged2.txt
```
##### ファイル削除

```bash
$ git rm ｛ファイル名｝
$ git status
Changes to be committed:
	deleted:    delete_soon.txt
```

##### 変更や削除をキャンセルしたい場合

```bash
// ①
// staging areaへのaddキャンセル
// ※staging areaの変更をリポジトリで上書き
$ git restore --staged ｛ファイル名｝

// ②
// working directoryのキャンセル
// ※working directoryの変更をstaging areaで上書き
$ git restore ｛ファイル名｝
```
①だけだと、working directoryに変更や削除は残る。全てやり直したい場合は、①②どちらも行うこと。
削除キャンセルために、リポジトリからpullするなどしてもワーキングディレクトリでの削除がリポジトリよりも後の行為なので削除したことは残ってしまう。

# 他のブランチへ更新を反映する

- [ローカルリポジトリへのマージ](#ローカルリポジトリへのマージ)
- [リモートリポジトリへのマージ](#リモートリポジトリへのマージ)
- [fork元リポジトリへのマージ](#fork元リポジトリへのマージ)

## ローカルリポジトリへのマージ

```bash：差分を確認してマージ（Fast-forward）
$ git checkout main //作業ブランチではなくマージ先のブランチに切替（ここだとmain）
$ git diff main new-feature
diff --git a/README.md b/README.md
index e6200e2..38a4340 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
 # my-git-practice
 Git練習用。テスト更新。
+`new-feature`ブランチで変更
\ No newline at end of file

$ git merge new-feature
Updating fe432e4..a961c1f
Fast-forward
 README.md | 1 +
 1 file changed, 1 insertion(+)
```

### mergeについて
いくつか種類があります。

#### Fast-forward
ブランチ作成からマージまでの間、マージ先での変更がなかった場合

```bash:
・main -(commit0)-------------------(commit1)------------->
                 |                   ∧merge
                 ∟other ----->(commit1)------------------>
```
#### Automatic merge
ブランチ作成からマージまでの間、マージ先での変更があったがコンフリクトしなかった場合
Gitは自動的に差分をマージした新しいコミット（merge commit）を作成する。

```bash:
・main -(commit0)----(commit2)------------(commit3)-------->
                 |                          ∧merge
                 ∟other ----->(commit1)------------------->
```
####手動マージ（Conflictが起きてAutomatic mergeされなかった場合）
ブランチ作成からマージまでの間、マージ先での同じファイルへの変更があるような場合

```bash:
・main -(commit0)----(commit2)------------(×)-------------->
                 |                       　∧※merge
                 ∟other ----->(commit1)------------------->
```
conflictが起きた状態、もしくは別の理由でGitによるmergeができなかった場合、
マージファイルはMERGINGに入るため、そのファイルを手動でコミットします。

```bash:conflict（マージ元のブランチ名）とmainがコンフリクトした場合
$ git merge conflict
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

$ git status
（略）
Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

$ subl README.md //テキストファイルを開き目で変更を修正していく
```
このようにコンフリクトしている物が両方含まれたファイルが開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/411a5dfa-b41e-af98-6eb6-a33b6f840702.png)
最終的にコミットしたい形に修正します。（Gitにより出力されている<<<<HEADなども削除します）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/b50b2b37-53c6-36c8-27b2-840a1f560435.png)

p4mergeを使ったマージは以下の通りに行います。

```bash:origファイルはgitignoreに追加して定期的にcleanするのも良い
$ git mergetool // マージツールが開くので編集して保存
$ rm README.md.orig // マージツールで保存すると変更前のファイルができるので削除
```

修正が終わったらadd/commitしていきます。

```bash:addの時点でbothmodifiedが解消しています
$ git add README.md
（略）
	modified:   README.md

$ git commit -m "resolve conflict"
```

## リモートリポジトリへのマージ
### pullとpush
チーム開発の場合、自身がローカルで作業始めた後にリモートリポジトリ側に更新がかかっている可能性があります。

```bash:リモートリポジトリmainのコミットが先に進んでいる状態でローカルmainからpushした時のエラー
$ git push origin main
To github.com:c3drive/my-git-practice.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'git@github.com:c3drive/my-git-practice.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```

そのため、pull（他の人の更新を今自分が作業しているブランチに反映）してからpushするようにしましょう。

```bash:この結果は変更がなかった場合の表示
$ git pull origin main // 作業ブランチではなく元のブランチ（main）からpullする
From github.com:c3drive/my-git-practice
 * branch            main       -> FETCH_HEAD
Already up to date.
```
pullは、fetch+mergeですので[ローカルリポジトリへのマージ](###mergeについて)と同様コンフリフトが起こることがあります（実務ではよく起こる）。
コンフリクトが起きた場合、[手動マージ](####手動マージ（Conflictが起きてAutomatic mergeされなかった場合）)を行います。
リモートリポジトリの更新を別の人が行っている場合、どちらを生かすべきか更新者に確認をします。
再度add/commitまで行った後のログを確認すると、リモートは`f69454e`が最新、ローカルは`d3dbe60`が最新、HEADは両者のマージコミットが作成されていることがわかる。

```bash:驚きの見辛さ
my-git-practice (:conflict-remote) :$ git log --oneline --graph
*   36d0396 (HEAD -> conflict-remote) resolve conflict
|\
| * f69454e (origin/main, origin/HEAD) Update README conflict
* | d3dbe60 Update README conflict-remote
|/
* 3638894 (main) Update readme on GitHub
```
 
問題なければpush（`git push <リモートリポジトリリファレンス> <ローカルリポジトリ>`）

```bash:
$ git push origin update-readme // mainではないので注意
```

### pull request
GitHubに移動して[リポジトリ] - [Pull requests]タブを選択し[New pull request]ボタンを押下します。
以下の画面になるので、マージ先（ここではmain）とマージ元を指定し、変更内容に問題がなければ、[Create pull request]を押下します。
![スクリーンショット 2021-02-20 19.27.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/364d2692-6fa5-2838-d2c7-c6ad558fc23e.png)
![スクリーンショット 2021-02-20 19.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/568ea5de-5204-7c1d-cca4-f32d8baa9274.png)

### reviewとmerge（チーム開発の場合、原則pullrequestした人以外が行う）
GitHubに移動して[リポジトリ] - [Pull requests]タブを選択しリクエストをreviewし、問題がなければ[Merge pull request]を押下します。
特にコメントに変更がなければそのまま[Confirm merge]押下。
![スクリーンショット 2021-02-20 19.37.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/e68abfef-98bf-903e-3e86-1db575ccf60a.png)

### リモートリポジトリの変更をローカルリポジトリに反映する（pull）
現時点で、前手順でマージしたmainのコミットポイントがリモートリポジトリにしかありません。
まずはブランチをmainに変更します。

```bash:*がmainについていればOK
$ git checkout main
$ git branch
* main
  update-readme
```
pullします。

```bash:
$ git pull origin main
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (1/1), done.
From github.com:c3drive/my-git-practice
 * branch            main       -> FETCH_HEAD
   ce4e1c0..64558cc  main       -> origin/main
Updating ce4e1c0..64558cc
Fast-forward
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
```
なお、ローカルmainは今後も開発時の元となるためできるだけリモートmainに近づけておくことが望ましいです。
対して、今回の場合update-readmeは役割を果たしているためpullせず削除しています。
また別の作業があったら、別の新しいbranchを作成します。

## fork元リポジトリへのマージ
### pullとpush
リモートリポジトリの時と基本的な流れは変わりませんが、
ここでpullする先はfork元、などの相違点に注意します。

```bash:upstreamは事前にセットしたfork元を示すリモートリファレンス名
$ git pull upstream main
From github.com:D-S-Hub/git-practice
 * branch            main       -> FETCH_HEAD
 * [new branch]      main       -> upstream/main
Already up to date.
``` 
問題なければpush（`git push <リモートリポジトリリファレンス> <ローカルリポジトリ>`）

```bash:ここはoriginへpush
$ git push origin git-practice
```

### pull request
GitHubに移動して[リポジトリ] - [Pull requests]タブを選択し[New pull request]ボタンを押下します。
以下の画面になるので、マージ先にfork元を指定し、マージ元を指定し、変更内容に問題がなければ、[Create pull request]を押下します。
![スクリーンショット 2021-05-26 20.04.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/ca6a0afc-fee6-fce5-c93f-b13f078b80bc.png)
pull requestを出す。ここで書くコメントはfork元のルールに従った形式にする。
指定がない場合であってもリクエストの理由や修正内容は丁寧に書きます。画像のようなコメントではダメです。
![スクリーンショット 2021-02-20 19.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/568ea5de-5204-7c1d-cca4-f32d8baa9274.png)

### reviewとmerge
fork元の管理人が行います。


#その他
######gitignoreのサンプル
[https://github.com/github/gitignore](https://github.com/github/gitignore)

######gitignoreの確認と削除
```bash
$ git clean -n // 追跡対象外のファイルを確認
$ git clean -f // 追跡対象外のファイルの削除
```

###### Gitリポジトリから普通のディレクトリにしたい場合

```bash:.gitファイルを削除することでgitリポジトリではなくなります
$ rm -rf .git
```
###### Gitのコミットログの確認

```bash:
$ git log
$ git log --oneline // originからどれくらい進んでいるか
```

###### fetch
pullは、fetch+mergeのため、単にfetchするということもできます

```bash
//fetch前
$ git status
On branch main
Your branch is up to date with 'origin/main'.

$ git fetch origin

//fetch後
$ git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

//"$ git checkout origin/main" するとリモートリポジトリの変更内容が見れる
```
###### rebase
将来マージしたいブランチに簡単にマージできるようにするため、mainと作業用ブランチがある場合、mainブランチを作業用ブランチにrebaseする
※コミットがなくなってしまうので一度pushしたコミットがある場合にはやらない

```bash
// 1.作業用ブランチでのコミット
$ git commit -m "update README"

// 2.mainブランチでのコミット
$ git commit -m "make anotherfile"

// 3.作業用ブランチに切り替えてmainをrebase
$ git checkout rebase-practice
$ git rebase main

// commitが枝分かれせず、1本に見えている（2のコミットログは削除され7c0b8ddができる）
$ git log --oneline --graph
* 7c0b8dd (HEAD -> rebase-practice) update README
* 7c77ba2 (main) make anotherfile
* b52de06 (upstream/main, origin/main, origin/HEAD) Initial commit

// このあとは普通にマージ
$ git checkout main
$ git merge rebase-practice
$ git log --oneline --graph
* 7c0b8dd (HEAD -> main, rebase-practice) update README
* 7c77ba2 make anotherfile
* b52de06 (upstream/main, origin/main, origin/HEAD) Initial commit

// rebase時にコンフリクトは起きた時はコンフリクト解消後以下を実行
$ git rebase --continue

// pullもmergeではなくrebaseすることも可能
$ git pull --rebase origin main

// デフォルトでpull時にrebaseする
$ git config --global pull.rebase true
```
###### stash
Workingディレクトリ、Stagingエリアの作業中の内容を一時待避できる。
待避後WorkingディレクトリとStagingエリアはクリアされる。
戻す時は、元のブランチである必要はなく、戻す操作をする時のブランチに戻せるため、作業ブランチを誤っていた場合の資産移動などにも使える。

```bash:stashへの追加と一覧表示
$ git status
modified:   README.md　// modifiedがあることを確認

$ git stash　// stash

$ git status
nothing to commit, working tree clean //clean

$ git stash list　// stash一覧
stash@{0}: WIP on main: 3bd5579 update anotherfile
```

```bash:stashからの戻しと削除（戻しただけでは削除されない）
$ git stash apply //戻し
$ git shash drop //削除

$ git stash apply stash@{<i>} //特定のstashをapply
$ git stash drop stash@{<i>} //特定のstashをdrop
```
apply時にstash対象がWorkingディレクトリにある場合、エラー
apply時にstash対象がStagingエリアにある場合、コンフリクトが起こるのでマージする（マージ後はのアクションはcommit）

```bash:その他
$ git stash -u //untrackファイルもstash
$ git stash -a //gitignoreファイルもuntrackファイルも全てstash
$ git stash save "<コメント>" //stashにコメントをつける
$ git stash show stash@{<i>} //特定のstashリファレンスを参照
$ git stash pop //spplyとdropを同時に行う
```

`$ git stash show stash@{<i>}`は、untrackファイルだと何も表示されない。

###### tag
最新のコミットにタグをつけます。

```bash:
$ git tag <tagname>　 <commitID> //commitID未指定の場合は最新のコミットが対象　
$ git tag -a <tagname>　//エディタが起動するのでコメントを記載
$ git tag -a <tagname>　-m "<コメント>"
```
tag情報をリモートリポジトリに反映する

```bash
$ git push origin <tagname>　 //特定のタグ
$ git push origin --tags //すべてのタグ
$ git push origin :<tagname> //リモートリポジトリからタグを削除
```
pushされたタグはtagsで確認可能
![スクリーンショット 2021-07-07 20.33.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/c237e688-baf6-f2dd-a3fe-4d4b5f096f8f.png)

###### submodule
サブモジュールにしたい、リポジトリにてパスをコピー
URL：[リポジトリ] - [code] - [SSH] - クリップボードのマーク押下

```bash:
$ cd <メインとなるリポジトリのディレクトリ>
$ git submodule add <コピーしたパス>
$ ls -la
drwxr-xr-x  10 yukokanai  staff  320  7  7 21:17 .
drwxr-xr-x   7 yukokanai  staff  224  7  7 20:41 ..
drwxr-xr-x  16 yukokanai  staff  512  7  7 21:23 .git
-rw-r--r--   1 yukokanai  staff   92  7  7 21:17 .gitmodules //サブモジュール追加時に作成
-rw-r--r--   1 yukokanai  staff   79  5 23 21:59 README.md
drwxr-xr-x   4 yukokanai  staff  128  7  7 21:17 sub-project //追加されたサブモジュール
$ git add . //.gitmodules と　sup-projectをadd
$ git commit -m "<コメント>"
$ git pull origin
$ git push origin main //リモートリポジトリにpush
```
サブモジュール@<参照しているコミット>がリンクになっており、リンク先は元のリポジトリにつながっている。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/d04f19a8-716d-b56d-1fd8-3ccbc6333898.png)

サブモジュールは更新されるので適宜pullする

```bash:
$ git submodule foreach 'git pull origin main'
$ git add . //サブモジュールの更新分をadd
$ git commit -m "<コメント>"
$ git pull origin
$ git push origin main //リモートリポジトリにpush
```

すでにsubmoduleがあるリポジトリをクローンした場合、submoduleのディレクトリは空でcloneされるため、初期化・更新する必要がある

```bash:サブモジュールの中に入って実行する必要がある
$ git clone <サブモジュールを含むリポジトリのコード>
$ cd <メインプロジェクト>/<サブモジュールのディレクトリ>
$ git submodule init
$ git submodule update
```
オプションを指定することで初期化と更新まで行うことも可能

```bash:
:$ git clone --recurse-submodules <サブモジュールを含むリポジトリのコード>
````
###### git-flow, GitHub Flow
git-flowの考え方。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f35333330392f30363134303132312d613062362d343237662d633134392d3638353863313439373338652e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/0073a3ab-0305-8626-98f1-918b4204a576.png)
GitHub flowは、git-flowを簡易化したもの。master(main)は常にデプロイできる状態であることは変わらない。

###### README.md(markdown記法）の書き方
5W1Hを意識：
1. そのプロジェクトが行うこと
2. なぜそのプロジェクトが有益なのか
3. どうやってそのプロジェクトを使うのか
4. ヘルプや詳細情報をどこで得ることができるのか(wikiへ書きリンク貼るのが一般的）
5. そのプロジェクトは誰がメンテナンスしているのか

markdown記法：[cheatsheet](https://guides.github.com/features/mastering-markdown/)
markdownの確認：
1. sublimeにて、cmd+shift+P、install package> Markdown HTML Preview
2. sublimeにて、README.mdを開きながら、controle+shift+m

GIF作成：
1. QuickTimeなどで動画撮影し、[convertio](https://convertio.co/ja/)　などでgifに変換
2. プロジェクト配下にimagesなど作成しgifを格納]
3. README.mdに以下を記入
`![Alt Text](images/sample.gif)`

###### GitHubにナビゲーションバーを表示させるChromeアドイン
[Octotree - GitHub code tree](https://chrome.google.com/webstore/detail/octotree-github-code-tree/bkhaagjahfmjljalopjnoealnfndnagc/related?hl=ja)

###### GitHubにてカンバンを実現するChromeアドイン
[ZenHub for GitHub](https://chrome.google.com/webstore/detail/zenhub-for-github/ogcgkffhplmphkaahpmffcafajaocjbd/related)

###### revert
打ち消しのコミットを新しく作ってmainは打ち消しコミットが最新となる。
コミット履歴を書き換えないので機密情報の打ち消しなどには使えない。

```bash:ローカルの場合
$ git log --oneline
b949956 update README.md

$ git revert HEAD

$ git log --oneline
9b1924a (HEAD -> feature) Revert "update README.md"
b949956 update README.md
```

リモートリポジトリでマージまで行ってしまった場合
![スクリーンショット 2021-07-11 13.39.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/35ec3e06-3f61-0ae2-c60c-5d84dfa58fcb.png)
![スクリーンショット 2021-07-11 13.40.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380300/ea3c551e-3ebf-3b27-4f9d-5334b88766f8.png)
Revertボタンを押下して、Revertのpull requestを作成しmerge

```bash:merge後のコミット履歴
$ git log --oneline
fbe18c7 (HEAD -> main, origin/main, origin/HEAD) Merge pull request #6 from c3drive/revert-5-feature
540b7de Revert "Feature"
46414c7 Merge pull request #5 from c3drive/feature
ffc7326 (origin/feature, feature) update README.md mistake2
```

###### reset
コミット履歴を書き換える。

```bash:
$ git reset HEAD^
```
オプションの使い分け

 | working directory | staging area
------------ | ------------- | -------------
--soft | keep | keep(*3)
-- mixed(default) | keep | reset
-- hard| reset | reset

* reset 指定したコミットIDの状態にそのエリアが上書きされる
* keep 指定したコミットIDの状態にエリアが上書きされるが、そのエリアに変更がある場合、上書きされない。


###### commit済みのファイル/ディレクトリをgit管理対象から除外
まずは`.gitignore`に追加。
その後コミットしてしまったものを削除します。

```bash:--cachedをつけないと本体からも削除されるので注意
$ git rm --cached articles // ファイル
$ git rm -r --cached articles // ディレクトリ
$ git add . //deleteを追加
```