私版 Gitまとめ

## はじめに

いまさらGitコマンドの解説記事を新しく書いても、誰も必要としていないだろうということは、うすうす気づいています。でも自分はとても忘れっぽいので、どこかにキチンとまとめておき、いつでも見直せるようにしておかないと、不安なんです。なによりも自分のため、大事なことから順番に、わかりやすくGitをまとめてみたいと思います

## 0. 最初にやるべきこと

自分の名前とメルアドを設定する

```bash
git config --global user.name "Isamu Suzuki"
git config --global user.email isamu@example.com
```

### git configコマンドとは？

```bash
# 設定内容をリスト出力する（system, global, localの順）
git config --list

# 上のコマンドと同じ
git config --system --list
git config --global --list
git config --local --list
# --system ... gitコマンドをインストールしたディレクトリにある
#              gitconfigファイルの内容を表示
# --global ... HOMEディレクトリにある.giconfigファイルの内容を表示
# --local ... 対象リポジトリにある.git/configファイルの内容を表示
```

## 1. gitコマンドの基本操作

### 自分で新しいプロジェクトを始める場合

```bash
# リポジトリを初期化する
git init

# そこにあるすべてのファイルを追加する
git add .

# 最初のコミット
git commit -m "Initial commit"

# リモートリポジトリを登録する
git remote add origin git@bitbucket.org:hoge/fuga.git

# リモートリポジトリに初めてプッシュする
git push -u origin master

# リモートリポジトリにプッシュする（2回目以降）
git push origin master
```

### 既存のプロジェクトに参加する場合

```bash
# リモートリポジトリからプルする
git clone git@bitbucket.org:hoge/fuga.git

# 自分が更新したファイルを追加する
git add hoge.txt

# コミット
git commit -m "docs: add comment"

# リモートリポジトリにプッシュする
git push origin master
```

## 2. コミットメッセージには、プレフィックスをつける

- `feat:` ... 新機能
- `fix:` ... バグフィックス
- `refactor:` ... 新機能でもバグフィックスでもないコード変更
- `perf:` ... パフォーマンス向上
- `test:` ... テストコードの追加・修正
- `style:` ... コードの意味に影響しない変更（空白、フォーマット、セミコロン）
- `docs:` ... ドキュメントだけの変更
- `chore:` ... 雑用（ビルドプロセスの変更、ツールやライブラリの追加削除）

## 3. ローカルブランチの基本操作

```bash
# issue1というブランチを作成する
git branch issue1

# ブランチの一覧を表示する
git branch
#=> *master
#=>  issue1

# ブランチを切り替える
git checkout issue1

git branch
#=>  master
#=> *issue1

# (option) ブランチの作成とチェックアウトをまとめて行う
git checkout -b issue2

# issue1で行った変更をmasterに取り込ませる
git checkout master
git merge issue1

# ブランチを削除する
git branch -d issue1
```

### git mergeコマンドとは？

HEAD（現在使用しているブランチの先頭）が指しているブランチに、指定したブランチを取り込む

```bash
# masterブランチをチェックアウトする
git checkout master

# masterブランチにissue1ブランチを取り込む
git merge issue1
```

### git mergeコマンドを実行して、競合があった場合は？

```bash
git merge issue2
# CONFLICT (content): Merge conflit in myfile.txt
# Automatic merge failed: fix conflicts and then commit the result.
```

コンフリクト（競合）があったというメッセージが表示される。競合があった箇所に、Gitが差分を挿入しているので、これを修正する。競合箇所の修正が終わったら、改めてコミットする

```bash
git add myfile.txt
git commit -m 'issue2ブランチをマージ'
```

## 4. コミットに関してよく行う操作

### コミットを取り消す

```bash
# 直前のコミットを取り消す（コミットのみ取り消す）
git reset --soft HEAD^

# 直前のコミットを取り消す（まったくなかったことにする）
# 新規ファイルは消えるし、編集内容も失われるので要注意
git reset --hard HEAD^
```

リモートにまでプッシュしていた場合は？

```bash
# 1. 強制的に同調させる
git push -f origin master

# 2. git resetは使わずに、取り消したいコミットを
#    打ち消すようなコミットを新しく作成する
git revert f5716bb --no-edit
#=> Revert "<previous>" というコメントでコミットされる
git push origin master
```

### コミットを修正する

```bash
git commit --amend -m "new message"
git commit --amend --author "Isamu Suzuki <isamu@example.com>"

# 変更を確認する
git log -1 --pretty=full

# リモートにまでプッシュしていた場合は、強制的に同調させる
git push -f origin master
```

git commitは、エディタが立ち上がるので、あらかじめ使い慣れたエディタを設定しておくと便利

```bash
# エディタをVimに設定する
git config --global core.editor 'vim -c "set fenc=utf-8"'
```

## 5. ブランチに関してよく行う操作

### 遡って（さかのぼって）ブランチ分けする

ローカルのmasterブランチに3回コミットをした後に、それらは新しいnew1ブランチにコミットすべきだったことに気づいたとする

```bash
# リモートのmasterブランチを追跡する、ローカルのnew1ブランチを作成する
git branch new1 origin/master

# 新しいブランチに切り替える
git checkout new1

# 新しいブランチに移したいコミットを1個づつチェリーピックする
git cherry-pick m0001
git cherry-pick m0002
git cherry-pick m0003

# masterに切り替える
git checkout master

# コミットを削除する
# （ヘッドから3個削除する場合のコマンド）
git reset --hard HEAD~3

# 強制的にリモートにプッシュする
git push -f origin master
```

## 6. リポジトリに関してよく行う操作

### ローカルをリモートに強制一致させる

```bash
# リモートリポジトリの情報をすべてローカルに取得する
git fetch origin

# ローカル内で状態を動かす
git reset --hard origin/master
```

### 手元にないリモートブランチを取得する

```bash
# リモートからデータをすべて取得する
git fetch origin

# originのdevelopブランチを追跡するローカルのdevelopブランチを作成する
git branch develop origin/develop

# ローカルのブランチを確認する
git branch
#=>  develop
#=> *master

# developブランチをチェックアウトする
git checkout develop

### 以下は絶対にやってはいけない ###

git pull origin new-branch:new-branch
#=> new-branchの内容が、現在のローカルブランチにマージされてしまう。
#=> 例えば、masterブランチにいたならば、masterブランチにマージされる
```

### リモートブランチを削除する

```bash
# リモートのhogeブランチを削除する
git push :hoge

### 以下解説 ###

# このコマンドには省略がある
git push origin hoge

# 省略なしバージョン
git push origin hoge:hoge

# ローカルのブランチをリモートのブランチにプッシュする
git push origin {ローカル}:{リモート}

# ローカルを空白にする => リモートのブランチを削除する
git push origin :{リモート}
```

### リモートリポジトリを変更する

```bash
# 現在のリモートリポジトリを確認する
git remote -v
# origin  git@bitbucket.org:hoge/fuga.git (fetch)
# origin  git@bitbucket.org:hoge/fuga.git (push)

# リモートリポジトリを変更する
git remote set-url origin {新しいURL}
```

## 7. Gitのサブモジュールを使う

あるGitリポジトリを別のGitリポジトリのサブディレクトリとして扱うことができるようになる

```bash
git submodule add https://github.com/laradock/laradock.git
#=> (1) .gitmodulesファイルが出来上がる
#=> (2) ディレクトリだけが取り込まれる
```

`.gitmodules`ファイル

```text
[submodule "laradock"]
  path = laradock
  url = https://github.com/laradock/laradock.git
```

Visual Studio Codeのソース管理では、2つのソース管理プロバイダーがあるのが見える

## 8. `.gitignore`ファイルを使いこなす

リポジトリ管理で追跡したくないファイル・フォルダは、`.gitignore`ファイルを作成してそこに書き込んでおくと、無視される

`.gitignore`ファイルの例

```text
__pycache__/
.vscode/
Include/
Lib/
Scripts/
pyvenv.cfg
```
### その中にあるファイルは追跡したくないが、フォルダだけは、クローンしたときにちゃんと作成したい場合

例えばtempフォルダを用意して、スクリプトが走った後は、必ずそこにログファイルを書き出すとする。tempフォルダがないと、スクリプトがエラーになってしまうが、その一方で、出力するログファイルは、リポジトリに登録する必要はないような時は、以下のように書き、tempフォルダに`.gitkeep`という空ファイルを置いておく

```text
temp/*
!.gitkeep
```

`temp/`とフォルダ名を書いてしまうと、驚きマークを使っても除外できなくなるので、`temp/*`で、「その中にあるすべてのファイル」を無視するように指示してから、驚きマークで、`.gitkeep`ファイルを除外する

## 最後に

間違いがあったら指摘してください。よく使うGitコマンドがよくまとまっていると思ったら、いいねボタンをクリックしてください。励みになります