新人研修で詰んだ私が、Gitの基礎をマスターした話【コマンド操作】

本記事では、Gitの利用について初心者向けに説明します。この記事を読めば全くGitに触れたことがない人が、個人開発で履歴管理ができ、簡単なチーム開発に参加できるようになれると思います。多くの企業では、Gitを使った開発を行っているので、これから企業でエンジニアになる人にとって、Gitの理解は必至です。また、履歴を残しながら開発できるので、Gitは個人開発においても非常に便利です。そこで、本記事は[わかばちゃんと学ぶ Git使い方入門](https://amzn.to/4mnjDAB)の内容を参考に、Git初心者に向けて、Gitとは何か、ローカル、リモート環境での利用についてまとめました。本書は主にGUIでの操作（クリックでの操作）を基本としていますが、[コマンドを用いた操作方法もネット上に公開されています](https://www.r-staffing.co.jp/engineer/entry/20190621_1)。

# 目次

- [1 記事を書こうと思った理由](#1-記事を書こうと思った理由)  
- [2 環境設定](#2-環境設定)  
- [3 個人開発（ローカル環境）](#3-個人開発ローカル環境)  
  - [3.1 リポジトリを作る](#31-リポジトリを作る)  
  - [3.2 変更を記録する](#32-変更を記録する)  
  - [3.3 過去の状態に戻す](#33-過去の状態に戻す)  
- [4 共同開発（ローカル＆リモート環境）](#4-共同開発ローカルリモート環境)  
  - [4.1 SSHの設定方法](#41-sshの設定方法)  
  - [4.2 リモートリポジトリをコピーする](#42-リモートリポジトリをコピーする)  
  - [4.3 ブランチを作る](#43-ブランチを作る)  
  - [4.4 ブランチを結合（マージ）する](#44-ブランチを結合マージする)  
  - [4.5 プッシュしよう](#45-プッシュしよう)  
  - [4.6 プルしよう](#46-プルしよう)  
  - [4.7 プルリクエストからマージまで](#47-プルリクエストからマージまで)  
- [5 Git中級編](#5-git中級編)  
  - [5.1 バージョン管理しなくてもいいファイルを無視する](#51-バージョン管理しなくてもいいファイルを無視する)  
  - [5.2 ブランチの運用方法](#52-ブランチの運用方法)  
  - [5.3 親リポジトリのコミットを取り込むには](#53-親リポジトリのコミットを取り込むには)  
  - [5.4 過去に戻って新規ブランチを作成し作業をやり直したい](#54-過去に戻って新規ブランチを作成し作業をやり直したい)  
  - [5.5 過去のコミットを打ち消したい](#55-過去のコミットを打ち消したい)  
  - [5.6 履歴を一直線にしたい](#56-履歴を一直線にしたい)  
  - [5.7 コミットを1つにまとめる](#57-コミットを1つにまとめる)  
  - [5.8 不要なブランチを削除する](#58-不要なブランチを削除する)  
  - [5.9 コミットメッセージの修正](#59-コミットメッセージの修正)  
  - [5.10 見込コミットのファイルを一時保存する](#510-見込コミットのファイルを一時保存する)  
  - [5.11 別のブランチから特定のコミットを取り込みたい](#511-別のブランチから特定のコミットを取り込みたい)  
  - [5.12 コミットにタグをつける](#512-コミットにタグをつける)  
  - [5.13 コンフリクトが起きたら](#513-コンフリクトが起きたら)  
- [6 Gitを使うメリット](#6-gitを使うメリット)  
  - [6.1 履歴が残せる](#61-履歴が残せる)  
  - [6.2 情報の透明化](#62-情報の透明化)  
  - [6.3 効率的なコミュニケーション](#63-効率的なコミュニケーション)  
- [7 Gitを使う際のベストプラクティス](#7-gitを使う際のベストプラクティス)  
  - [7.1 いつコミットするべきか？](#71-いつコミットするべきか)  
  - [7.2 いつプルするべきか？](#72-いつプルするべきか)  
  - [7.3 いつプッシュするべきか？](#73-いつプッシュするべきか)  
  - [7.4 いつプルリクエストを送るべきか？](#74-いつプルリクエストを送るべきか)  

# 1. この記事を書こうと思った理由
新卒データサイエンティストとして採用された際、同期と共同開発をする研修がありました。周りの同期が謎のGitコマンドを打ちながらコミットをしていく中、私はプルって何？コミットって何？そもそもなんでGit使うの？と開発以前の段階でした。開発中もGitの使い方が分からず、結局ローカル環境はボロボロで、同期に全てのプルリクエストやマージをしてもらい、研修を終えました。その週末に、[わかばちゃんと学ぶ Git使い方入門](https://www.amazon.co.jp/%E6%94%B9%E8%A8%822%E7%89%88-%E3%82%8F%E3%81%8B%E3%81%B0%E3%81%A1%E3%82%83%E3%82%93%E3%81%A8%E5%AD%A6%E3%81%B6-Git%E4%BD%BF%E3%81%84%E6%96%B9%E5%85%A5%E9%96%80%E3%80%88GitHub%E3%80%81SourceTree%E3%80%81%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E6%93%8D%E4%BD%9C%E5%AF%BE%E5%BF%9C%E3%80%89-%E6%B9%8A%E5%B7%9D-%E3%81%82%E3%81%84/dp/4863543433)を読んで、やっとGitの使い方が分かったので、私のようなGit未経験者にGitを使った開発環境を知って欲しくこの記事を書いています。学習して思ったのは、**Gitは簡単**ということです。もちろん裏の構造の理解や仕組みを理解するのは難しいですが、本記事を読めば業務で使うのに十分なレベルに到達するのは簡単だと思います。

# 2. 環境設定
基本的にはコマンドプロンプト（Macならターミナル）での操作について解説します。GUIでの操作（クリックでの操作）も可能ですので、そちらを知りたい方は[SourceTree](https://www.sourcetreeapp.com)をインストールして、操作方法を確認してみてください。ただ、GUIでの操作よりもコマンドで操作した方が覚えることも少ないですし、ミスが起こりづらいです。私もそうですが、初心者はコマンドでGitを操作して、上手くいっているかを視覚的に確認するために、SourceTreeを利用すると良いでしょう。


# 3. 個人開発（ローカル環境）
まずは、個人での開発を想定した内容を説明します。次の章で共同開発を想定した場合のGitの使い方を解説しますが、自分のローカル環境とリモート環境の両方を操作する必要があります。そのため、まずはローカル環境でのGitの操作を覚える必要があります。

そもそもローカル環境とは、今現在使っている自分のパソコン上の環境のことを指します。Gitにおいてローカル環境という言葉を使いときは主に以下のような意味を持ちます。
- ネットワークに接続せず、クラウドやサーバーとやり取りしない、自分のPCだけで完結する操作範囲
- ローカルリポジトリ（自分のPC内に作成したGitのデータベース）の操作
- ファイルの変更、コミット履歴の管理、ブランチの操作などを、自分のPC上で行うこと

## 3.1 リポジトリを作る
Gitにおいて、リポジトリは貯蔵庫のような物を指します。リポジトリは過去の状態を記憶できるので、ソースコードや元データなど様々なものを保存しておけます。とりあえず、ローカルPC上ではフォルダとほぼ同じものと理解しておいて問題ないと思います（厳密には隠しフォルダの.gitの中にGitのすべての情報が詰まっている）。
以下のコマンドで、リポジトリを作りましょう。
```
$ mkdir sample　（←sampleディレクトリを作成）
$ cd sample　（←sampleディレクトリに移動）
$ git init .　（←今いるディレクトリをGitリポジトリとして登録）
```
```
/Users/xxx/Documents/sample/.git/
```
のようなものが表示されればOKです。
また、ディレクトリ内で以下のような隠しフォルダがあれば、Gitリポジトリとして登録されています。Macの場合、command+Shift+.(ピリオド)のショートカットで隠しフォルダを表示/非表示にできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4072443/2be13b09-6790-4d24-ae1f-4672505020d5.png)

## 3.2 変更を記録する
今のリポジトリの状態を記録しておけば、後々今の状態に戻って来れます。リポジトリの状態を記録するには、**ステージ**して、**コミット**する必要があります。ステージで撮影台に乗せて、コミットで撮影するイメージです。
```
$ git status　←作業ディレクトリの状態を確認
$ git add ファイル名　←指定したファイルをステージする
$ git commit -m "コミットメッセージをここに書く"　←コミットメッセージを添えてコミットする
```

## 3.3 過去の状態に戻す
コミットしておけば、指定した状態のリポジトリを再現することができます。この作業を**チェックアウト**という。チェックアウトは今いるコミットを移動するだけで、過去の変更を消したわけではないので、最新の状態にも戻ることができます。
```
git log --oneline --graph　←コミットIDを確認する
git checkout <コミットID>　←指定したコミットに移動する
```
ここまでが、個人開発を前提としてGitの利用である。ここまででも十分に便利だが、Gitが真価を発揮するのは共同作業を行う場面においてである。Gitは分散型であるので、以下のような特徴があるため、共同開発においてよく利用される。
- オフラインでも仕事ができる
- 他の人に影響を及ぼさず色々実験ができる
- いざという時に復元しやすい

# 4. 共同開発（ローカル＆リモート環境）
[GitHub](https://github.com/)のアカウントが必要になるので、アカウントを持っていない人は作成しておいてください。
まずは、SSHを使ってリモートレポジトリにアクセスしてみましょう。

# 4.1 SSHの設定方法
SSH（Secure SHellの略）は安全性の高い通信方法の1つで、全ての通信が暗号化されて行われます。公開鍵と秘密鍵でアクセス認証するようになっている。SSH接続をしておかないと、自分のPCからリモートリポジトリに変更を加えたり、リモートレポジトリの状態をローカルに反映することができないので、以下の手順でSSH接続の設定を行いましょう。

1.　公開鍵と秘密鍵を作る
```
$ ssh-keygen -t ed25519 -C　←公開鍵と秘密鍵を作る
$ ls ~/.ssh ←鍵ができていることを確認
```

2.　秘密鍵を自分のパソコンに登録する
```
$ ssh-add ~/.ssh/id_ed25519
```
3.　公開鍵はGitHubへ登録する
```
$ pbcopy < ~/.ssh/id_ed25519.pub　←公開鍵をクリップボードにコピーする
```
ブラウザでGitHubを開いて公開鍵を追加する
1. Setting -> SSH and GPG keys
2. New SSH Keyをクリック
* 「Title」は、パソコン名にするとわかりやすいです。
* 「Key type」は、Authentication Keyのままにします。
* 「Key」欄に、さきほどコピーした公開鍵を貼り付けます。
* 最後に「Add SSH Key」ボタンをクリックします。

4.　SSH接続できることを確認する。
```
$ ssh -T git@github.com
```
「ed25519」というのは、署名方式暗号方式のひとつです。2023年現在、GitHubで推奨されている方法です。
秘密鍵は絶対に公開してはいけません。以下、注意する必要がある例。
- リポジトリの中に秘密鍵を置いていたり、ソースコードの中に直接秘密鍵を書いている
- どこかのサーバに秘密鍵をアップロードしてしまった
- 複数人で秘密鍵を共用している （秘密鍵をメールで送ったり、USBメモリに保存して渡すのもNG）

これでSSH接続が完了しました。それでは、リモートリポジトリを操作していきましょう。

# 4.2 リモートリポジトリをコピーする
実務では、共同で作業するマスターとなるリモートリポジトリがあります。案件に入った際や、マスターリポジトリに変更があったときなど、自分のリモートリポジトリやローカル環境にコピーする必要があります。リモートリポジトリをコピーする方法として、**フォーク**と**クローン**がある。フォークは他の人がGitHub上で公開しているリポジトリを自分のGitHubアカウントにコピーすることです。フォークはコマンドラインではできないので、Webでクリック操作をする必要があります。クローンはGitHub上のリモートリポジトリを自分のローカル環境にダウンロードすることです。企業ではフォークせずに、クローンだけすることが多いそうです。
```
git clone <クローンしたいリモートリポジトリのURL>
```

<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4072443/d431844e-f802-4924-9bb6-229abacb24d9.png" width="70%">
</div>

# 4.3 ブランチを作る
**ブランチ**とはポインタ（別の川）です。ブランチがあることで、複数人で並行して作業することが可能になります。簡単にいうと並行世界を作ることができる。
以下に、例としてprofileブランチを作成し、その中でファイルに変更を加えて、コミットする操作を書きます。
```
$ git checkout -b profile　←profileブランチを作成して、移動
$ git add <変更を加えたファイル名>　←ファイルの変更した後、ステージする　
$ git commit -m "hogehoge"　←コミットする
$ git checkout main　←mainブランチに戻る
```
通常、主となるブランチはmainと名付けられます。

# 4.4 ブランチを結合（マージ）する
ブランチを統合することを**マージ**するという。自分のブランチの変更をmainに追加したり、その逆でmainの変更を自分のブランチに変更したいときに行う。
```
$ git checkout <マージコミットしたいブランチ名>　←マージコミットしたいブランチに移動
$ git merge <マージしたいブランチ名>　←マージしたいブランチを指定してマージ
```
今回の例だと、`git checkout main`からの`git merge profile`という順に実行する。

# 4.5 プッシュしよう
ローカルで起きた変更をリモートに反映する作業を**プッシュ**という。
```
git push origin main
```

プッシュしようとしているリモートリポジトリを確認するには`git remote -v`。プッシュ先のリモートリポジトリを変更するには、`git remote set-url origin (リモートリポジトリのURL)`。
リモートリポジトリのURLは以下のようにSSH形式で上記に挿入しておく`git@github.com:hogehoge/hozihozi.git`
SSH接続しておくと、プッシュ時の認証を避けられるのでSSH接続しておくとここでも便利にGitが使えます。

# 4.6 プルしよう
リモートリポジトリの変更をローカルリポジトリに変更する作業を**プル**するという。いわゆるダウンロードに近い作業。リモートブランチをローカル上で追跡しているリモート追跡ブランチ（origin）があり、リモートブランチから、リモート追跡ブランチに情報を反映するfetchというコマンドと、追跡ブランチからローカルブランチに変更を反映するmergeコマンドの2つのコマンドの作業を同時に行うのがpullです。
```
$ git checkout <プルしたいブランチ名>　←プルしたいブランチに移動
$ git pull <リモートリポジトリ名> <ブランチ名>　←リモートリポジトリ上のコミットをローカルブランチに取り込む
```
リモートリポジトリのmainブランチをローカルリポジトリのmainにプルしたい場合は、`git checkout main`からの`git pull origin main`というコマンドを実行する。

# 4.7 プルリクエストからマージまで
フォークやクローン元のマスターリポジトリに自分のリモートリポジトリの変更提案を取り込んでもらう方法を**プルリクエスト**という。
プルリクエストは、ブラウザのGitHubから送ります。
修正が来たら、同じブランチに修正して再度コミットするだけでプルリクエストの内容も自動で更新される仕組みになっています。

ここまでが、Gitで共同開発をする際の基本的な知識です。以降は、Gitをより良く使うために知っておくと良い知識を紹介していきます。とりあえず、Gitが使える状態になりたいという方はここで離脱していただいても問題ないと思います。
# 5. Git中級編
ここからは、さらにGitを使いこなすための知識です。すぐに必要でなければ読み飛ばしてもOKです

# 5.1 バージョン管理しなくてもいいファイルを無視する
OSが自動生成するファイルやキャッシュ、容量が大きすぎるものは、バージョンを管理する必要がない、もしくは管理したくないかもしれません。そのような場合は、リポジトリ内にあるgitignoreファイルを書いて設定する。
gitignoreに関しては様々な記事がありますが、[こちらの記事がわかりやすいと思います](https://qiita.com/sf213471118/items/efbc0abf028a3ead72e7)。

# 5.2 ブランチの運用方法
ブランチの運用方法で有名なものに[GitHub Flow](https://zenn.dev/yukun369/articles/3b286fcb308e33)というブランチ運用方法があります。
GitHub Flowのブランチモデルに関して、簡単に記載します。
- mainブランチ
    - mainブランチの内容は常に安定していて、いつでも本番反映できる状態にしておきます
    - 基本的にmainブランチで作業することはなく、実際の作業はtopicブランチで行う
- topicブランチ
    - 新機能を追加したくなった、デザインを修正したくなったら、目的ごとにmainブランチから新たなブランチを生やし、そこで作業する
    -topicブランチの名前は、パッとみた時に想像できる名前にします

次にGitHub Flowの6つのルールについて解説します。
1. mainブランチはいつでも本番反映可能
1. 新しい作業に取り組む際は、その内容を表す名前のブランチを作る
1. ブランチを定期的にプッシュする
1. フィードバックや助言が欲しくなったら or mainブランチにマージできる準備が整ったら、プルリクエストを送る
1. mainブランチへマージできるのは、他のメンバーにレジューしてもらってOKが出たものだけ
1. mainブランチへマージされたら、直ちにリリースする

# 5.3 親リポジトリのコミットを取り込むには
気づいたら、フォーク元の親リポジトリが、自分のリモートリポジトリもはるか先にいるということはよくあります。その際、GitHub上でフォーク元の親リポジトリの変更を、自分のリモートリポジトリに簡単に取り組むことができます。
![Go to file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4072443/81ab6384-52c2-4677-951d-31ca7930358b.png)
画像元：https://ardalis.com/github-fetch-upstream/

# 5.4 過去に戻って新規ブランチを作成、作業をやり直したい
```
$ git branch <新しいブランチ名> <過去のコミットID>
```

# 5.5 過去のコミットを打ち消したい
**リバート**を行うと過去のコミットを打ち消すことができます。これは、過去のコミット自体を削除するのではなく、あくまでも反対の内容で新規コミットを作ることで、過去の変更を打ち消す作業にあたります。
```
git revert (コミットID)
```

# 5.6 履歴を一直線にしたい
**リベース**すると履歴を真っ直ぐにできるため、単にマージするよりも他の人と自分の変更履歴などが格段に見やすくなります。しかし、リベースはコミットを新たに作り直しているので、リモートリポジトリ上に存在しているブランチをリベースしてしまうと、普通の方法ではコミットできなくなってしまいます。慣れるまでは、リベースは使わずに、マージを使う方が吉。
リベースに関しては、こちらを参照　https://qiita.com/hinako_n/items/2e81141ce74b3b7d1d56

# 5.7 コミットを1つにまとめる
まだプッシュする前のローカルリポジトリ内のコミットに限り、**スカッシュ**でまとめられる。

# 5.8 不要なブランチを削除する
mainとマージして必要ではなくなったブランチを削除することもできます。リモートリポジトリ上のブランチを削除するのはGitHubのブラウザ上でできます。リモートリポジトリで削除したブランチを消すには、pruneコマンドを使います。
1. まずGitHubのブラウザ上でリモートリポジトリ上の不要なブランチを削除します
1. リモートリポジトリで削除したブランチの追跡ブランチは残っているのでそれらを削除します
```
git fetch --prune
```
これで、remotes/origin/ブランチ名 が消える
3. ローカルのブランチは以下のコマンドで削除
```
git branch -d <ブランチ名>
```

# 5.9 コミットメッセージの修正
直近のコミットなら、すぐに修正できます。
```
git commit —amend
```

# 5.10 見込コミットのファイルを一時保存する
**スタッシュ**を使うとできます。割り込み作業が入り、途中の作業をコミットしたくない時に便利です。

# 5.11 別のブランチから特定のコミットを取り込みたい
本来はBのブランチでコミットするはずが間違えて、Aのブランチでコミットしてしまった時、AからBにコミットをコピーできます。これはGitでは**チェリーピック**と呼ばれる動作。チェリーピックをしても元のコミット、この場合ではAのコミットは消えないので、消したい時は、チェリーピックしたあとでリバートする必要がある。
```
git cherry-pick (コミットID)　←任意のコミットを今いるブランチの上にコピーしてくる
```

# 5.12 コミットにタグをつける
以下のような場合には、目印となるタグをつけることが勧められています。
- アプリ開発でリリースした時にバージョン番号のタグをつける
- 受託開発で納品したときに日付のタグをつける
- Web開発でリニューアルオープンした時にタグをつける
```
$ git tag <タグ名>　←ローカルで新規タグを作る
$ git push origin <タグ名>　←タグをリモートリポジトリに共有する
$ git tag -d <タグ名>　←ローカルリポジトリのタグを削除する
$ git push origin --delete <タグ名>　←リモートリポジトリのタグを削除する
```

# 5.13 コンフリクトが起きたら
同じ行に同時に別々の修正がなされたときに発生する現象を**コンフリクト**と呼びます。コンフリクトが発生しても冷静に対処しましょう。コンフリクトの例として以下のパターンが多いです。
- Aさんが main に「ログイン画面の文言」を修正
- Bさんが別ブランチで同じ箇所の文言を変更
- Bさんが main をマージしようとしたとき、どちらの変更を正とすべきかGitが判断できない
対応としては、コンフリクトした点を修正してコミットするだけだが、どこでどのようなコンフリクトが発生しているかを確認する方が良いです。コンフリクトした後は以下の流れで対応すると良いです。
1. `git status`でコンフリクトが起きている箇所を確認する
1. コンフリクト箇所を修正する
1. `git diff`で変更内容を確認
1. 解決したらステージングしてコミットする
コンフリクトの箇所の発見や修正にはGitHubやSourceTreeの利用もおすすめ

# 6 Gitを使うメリット
Gitを使うメリットは主に以下の3つです。
- 履歴が残せる
    - 過去の変更が見れるかつ、過去の状態に簡単に戻せる
- 情報の透明化
    - 一箇所に全ての情報がまとまる
    - 他の人の変更履歴がわかる
- 効率的なコミュニケーション
    - 共同開発が容易になる

# 7 Gitを使う際のベストプラクティス
Gitは今やエンジニアにとって必須のバージョン管理ツールです。しかし、実務でのGit運用は、単にコマンドを覚えるだけでは不十分です。「いつ、何をすべきか」という判断ができることが、チーム開発ではとても重要になります。本記事のまとめとして、Git運用のベストプラクティスについて紹介します。

## 7.1 いつコミットするべきか？
Gitの基本は「こまめなコミット」です。作業の単位が大きくなればなるほど、後からのトラブル対応が難しくなります。コミットの目安として以下のようなタイミングがあります。
- 小さな機能や修正が完了したタイミング
- UIや文言の変更など、意味のある単位の変更を終えたとき
- 大きなロジック変更を始める前の区切りとして

また、コミットメッセージにも工夫が必要です。コミットメッセージには、何をどのように変更したかを記載するようにしましょう。

良い例：
```
若葉ちゃんのプロフィールの自己紹介が空白で表示されるエラーを修正し、正しい自己紹介文が表示されるようにした
```

悪い例：
```
プロフィールページのバグを修正した
```

## 7.2 いつプルするべきか？
リモートリポジトリには他の開発者の変更がどんどん入っていきます。そのため、作業中に自分のローカルだけが古い状態になってしまうことも。
プルのタイミング
- 作業を始める前：最新の状態を確認してから作業を始める
- プッシュする前：自分の変更が他人の変更と衝突しないかを確認する
この2つのタイミングでプルを行うだけで、コンフリクトの多くは未然に防げます。

## 7.3 いつプッシュするべきか？
プッシュは、ローカルの作業内容をリモートに反映する操作です。プッシュのタイミングを誤ると、レビューやチーム連携に支障が出ることも。
プッシュの目安
- 機能の実装や修正が一段落したとき
- プルリクエストを作成するとき
- 作業を共有したいとき
ただし、未完成・未確認のコードを上げると、CIのエラーや他の開発者の混乱につながるので、作業の途中経過をむやみにプッシュするのは避けるべきです。

## 7.4 いつプルリクエストを送るべきか？
GitHubやGitLabなどでは、「プルリクエスト（PR）」によって自分の作業を他人にレビューしてもらい、リモートのメインブランチにマージしていきます。
プルリクエストを送るべきタイミング
- 一つのタスクや機能の実装が完了したとき
- 動作確認が済み、CIテストをパスしているとき
- レビューを依頼したいとき

プルリクエストに書くべき情報
- 概要：何を変更したのか
- 背景：なぜこの変更が必要か
- 影響範囲：既存のどの機能に影響する可能性があるか
- 補足：スクリーンショットや参考リンクなど