Git運用、およびGitコマンドのまとめ

# はじめに

Gitを使用する際に、よく見るサイトや、Git運用、コマンドなどをまとめました。

- [Git - Book] (https://git-scm.com/book/ja/v2)
公式サイト。公式こそ正義。

- [サルでもわかるGit入門] (https://backlog.com/ja/git-tutorial/)
とてもわかりやすい入門サイト。


# Git運用について

- みんな好き勝手に、ブランチ名決めるとわかりづらい。基本的なブランチ名を決めよう
- Gitコマンドは、色々あってわかりづらい。運用手順と使用するコマンドを決めよう

というもの。代表的なのは、以下の3つ。
GitLab の公式ドキュメントがとてもわかりやすいので、こっちみた方がいいかもしれないです。

- [GitLab flowから学ぶワークフローの実践] (https://postd.cc/gitlab-flow/)

## Git-flowとは

Gitのプラグインを指します。また、そのプラグインを使って実現するGitのブランチモデル(運用手順みたいなもの)も総称してGit-flowと呼ぶこともあります。

- [git-flow cheatsheet](https://danielkummer.github.io/git-flow-cheatsheet/index.ja_JP.html)

![git-model@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149438/c07dfce8-5be1-9e67-5440-95d99cea0fe1.png)

- [A successful Git branching model](https://danielkummer.github.io/git-flow-cheatsheet/index.ja_JP.html)

ブランチ数や、運用手順がやや複雑ですが、これ以降に出てくるブランチ名や、運用の原点となっています。



## GitHub-flow

Git-flowだと運用が煩雑なので、GitHub-flowはシンプルになりました。

- [GitHub Flow](https://gist.github.com/Gab-km/3705015)

GitHub-Flowだと `master` ブランチと `feature` ブランチで構成されます。

- 本番用の`master`ブランチから、用途に合わせた名前のブランチ(ここでは`feature`と呼称。 Git-flowでいう、feature/hotfixブランチが近い)を作成。
- 作成した`feature`ブランチで作業を行い、作業が終わったらリモートブランチへpushする。
- GitHubの機能である `Pull Request` を使って、レビューが完了したら `master` ブランチへmergeする。
- マージ後の`master`は、すぐに本番へデプロイする。

GitHubの機能(Pull Request/Issues/継続的インテグレーションツール連携)の利用を前提とした運用手順です。

## GitLab-flow

ユーザに通知なく、リリースできないタイプのアプリだと、GitHub-flowだと面倒です。
GitLab-flowでは、リリースに関するブランチが追加されました。

- [GitLab flowから学ぶワークフローの実践] (https://postd.cc/gitlab-flow/)

- `production`ブランチを置くパターン
    - `master` とは別に、本番リリースする用の `production` を作成するもの。
    - `master` は完成品という点では変わらず、`production`はリリース時間を調整するもの。
- `production`/`pre-production`ブランチを置くパターン
    - ステージング(`master`)[^1]、プリプロダクション環境(`pre-production`)[^2]、プロダクション環境(`production`)[^3]を作成するもの。(環境に関する用語は、プロジェクトによって異なるので少しややこしい)
    - 面倒に見えますが、継続的デプロイが実施できる環境であれば問題ないという考え方。
- `stable`/`release`ブランチを置くパターン
    - 細かい版管理をするパターン。最新版`release`と、安定版`stable`
    - 最新版`release`と、安定版`stable`は両方とも本番。版が違うだけ。

GitHubクローンであるGitlabの機能(Merge Request/Issues/Gitlab CI・CD連携)などを前提としています。


# よく使うGitコマンド

GitHub-flowっぽい運用を想定して、使用するGitコマンドをまとめました。

## 一般的な操作

### ブランチの作成など

```shell
# ローカルリポジトリを作成
git init

# リモートリポジトリをローカルへコピー
git clone REPOSITORY_PATH

# 新規ブランチの作成
git checkout -b BRANCH_NAME
```

### インデックスにファイルを追加

```shell
# 作業ツリーにある新規作成/更新/削除されたファイルをインデックスに登録
git add --A

# -p : 変更差分を確認しつつ、インデックス登録できる

# 状態を確認
git status
```

### コミットとリモートリポジトリへのプッシュ

```shell
# コミットメッセージをつけてコミット
git commit -m 'MESSAGE'

# リモートリポジトリへ指定したブランチをpush
git push origin BRANCH_NAME

# リモートリポジトリへ現在のブランチをpush
git push origin HEAD

# --force-with-lease : リモートリポジトリのブランチを上書きしてpush、正確な動きはリンクを参照
```

- [it push --force-with-leaseはいつも安全？](https://qiita.com/upinetree/items/5d0b224b8e53ad276ea0)
- [Git - git-push Documentation](https://git-scm.com/docs/git-push)

### ブランチの削除

```shell
# マージ済みのブランチ削除
git branch -d BRANCH_NAME

# マージされていないブランチの削除
git branch -D BRANCH_NAME
```
## 最新masterの変更取り込み操作

### mergeによる最新masterの取り込み

すでにレビュー中で、他の開発者に影響が出るブランチは、mergeを使用して、最新のmasterを取り込みます。

```shell
# masterブランチへ移動
git checkout master

# masterブランチを最新の状態にする
git pull origin master

# 最新masterの変更を取り込みたいブランチへ戻る
git checkout BRANCH_NAME

# masterを使用して現在のブランチをmerge
git merge master
```

### rebaseによる最新masterの取り込み

レビュー前の、featureブランチなど他の開発者に影響が出ないブランチは、rebaseを使うことが多いです。

```shell
# masterブランチへ移動
git checkout master

# masterブランチを最新の状態にする
git pull origin master

# 最新masterの変更を取り込みたいブランチへ戻る
git checkout BRANCH_NAME

# masterを使用して現在のブランチをrebase
git rebase master
```

### rebase時にコンフリクトなどが起こる場合

```shell
# コンフリクトが発生してマージできなかったファイルを確認
git status

# コンフリクトが発生しているファイルを修正(手動)

# コンフリクト修正後、修正を反映するためにadd
git add FILE_PATH

# コンフリクトが修正した後に、rebaseを再開
git rebase --continue

# rebaseキャンセル
git rebase --abort
```

### リモートリポジトリに rebase した結果を反映させる時


```shell
# リモートリポジトリにすでにpushしたブランチがあり、それを上書きする時
git push origin BRANCH_NAME --force-with-lease
```

## 誤操作の修正に使用するコマンド

### ファイルを直前のコミット状態に戻したい時

```shell
# 全てのファイルをHEADの状態に戻す
git checkout HEAD .
```

### 直前のコミットを削除したい時

```shell
# 直前のコミットを削除(git reset --mixed HEAD^と同じ)
git reset HEAD^

# --soft : 作業ツリー(作業ディレクトリ)はそのまま、インデックス(ステージングエリア)もそのまま
# --mixed: 作業ツリー(作業ディレクトリ)はそのまま、インデックス(ステージングエリア)は削除
# --hard : 作業ツリー(作業ディレクトリ)、インデックス(ステージングエリア)共に削除
```

全てコミットは削除されるが、消え方が微妙に違う。HEADに関しては下記の記事を参照。

- [【やっとわかった！】gitのHEAD^とHEAD~の違い](https://qiita.com/chihiro/items/d551c14cb9764454e0b9)
- [7.1 Git のさまざまなツール - リビジョンの選択] (https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%83%AA%E3%83%93%E3%82%B8%E3%83%A7%E3%83%B3%E3%81%AE%E9%81%B8%E6%8A%9E)


### コミットメッセージを修正したい時

```shell
# コミット履歴を確認
git log

# 直前のコミットメッセージを修正 
git commit --amend

# メッセージ修正は vi と同じ要領

# コミット履歴を確認
git log
```
## レビュー/レビュー終了後の操作

### リモートブランチのローカルコピー

```shell
# リモートリポジトリとリモート追跡ブランチの同期
# -p オプションでリモートリポジトリで削除されたブランチをリモート追跡ブランチからも削除
git fetch -p

# リモート追跡ブランチからローカルブランチを作成
git checkout -b BRANCH_NAME origin/BRANCH_NAME
```

### マージした不要なローカルブランチの削除

```shell
# masterブランチへ移動
git checkout master

# masterブランチに対してマージ済みのブランチを表示
git branch --merged

# 不要なブランチの一括削除 grep および xargsを使って git branch -dを連続実行
git branch --merged | grep -v '*' | xargs -I % git branch -d %
```

- [Git 不要ローカルブランチを単語検索で一括削除](https://qiita.com/ryusukefuda/items/98e7e8d6c3b7486a407d)

# 最後に

あんまり使いませんが、`git rebase -i ` などを使ってコミット履歴操作など追加するかもしれないです。
GitHub-flowっぽい運用であれば、ここにあるコマンドで十分だと思います。

[^1]: 開発段階の動作確認、テストを行う、検証環境を指しているものと考えられる。
[^2]: リリース前確認、負荷テストなどを行う、本番環境と全く同じ構成の準本番環境を指しているものと考えられる。
[^3]: 本番環境を指している。