リポジトリで理解するGitコマンド

## はじめに
現在働きながらWebエンジニアになる為に[HappinessChain](https://happiness-chain.com/)というプログラミングスクールで学習しています。
今回はGitとGitHubについて一通り学習を終えたのでアウトプットも兼ねて記事を作成します。
本記事はGitで完結しており、Gitがインストールされている前提として話を進めていきます。
## GitとGitHubの違い
### Git
Gitはファイルのバージョン管理システムです。
Gitを使うとファイルの異なる状態（現在の状態と以前の状態）を保存しておけます。これを使って以前の状態に簡単に戻ることができ、新しい変更を追加することもできます。　　
これらはローカル上で行われます。
### GitHub
GitHubはGitで管理しているファイルをオンラインに保存し、他の人と共有するためのウェブサービスです。GitHubを使うことで複数の人が協力してプロジェクトを開発する際に、効率的に作業を進めることができます。
### なぜGitとGitHubを使うのか
- 多くの企業が導入している
- ローカル上とオンライン上にファイルを保管できる
- ファイルのバージョン管理が容易
- 誰が何の為にファイルを変更したか履歴を追える
- チーム開発を行う上で便利な機能が豊富
- 無料でオープンソース

## Gitの3つの主要エリア
Gitの仕組みを理解する上で3つのエリアについて説明します。
### ワークツリー
ワークツリーは現在作業しているディレクトリを指します。　　
実際のファイルが保存されている場所で、ここでファイルの編集や新規ファイルの作成を行います。
### ステージングエリア(インデックス)
ステージングエリアはローカルリポジトリにファイルを追加する前の待機場になります。　　
ワークツリーからこのステージングエリアにファイルを追加します。インデックスとも呼ばれます。
### ローカルリポジトリ
ローカルリポジトリはプロジェクトのファイルやバージョン履歴を保存する場所になります。
プロジェクトの完全な履歴も保存されており、追加されたファイルの情報や誰が何の為にファイルを追加したのかの情報もここに保存されます。

※ここから先に出てくるリポジトリとはローカルリポジトリを指しています。
## リポジトリの作成
Gitはリポジトリにファイルや履歴を保存する事で過去のバージョンに戻ったり、履歴を追う事が出来るのでした。
そのためGitでバージョン管理を行うには、初めにリポジトリを作成しなければなりません。
  
今回はデスクトップに空のgit_practiceディレクトリを用意しました。
以下のフローでgit_practiceにリポジトリを作成していきます。

1. `cd`コマンドでリポジトリを作成するディレクトリまで移動します。
   ```zsh
   $ cd ~/desktop/git_practice
   ```
   <br>
2. `git init`コマンドでディレクトリ内にリポジトリを作成します。
   ```zsh
   $ git init
   ```
   <br>
3. `ls -a`コマンドで.gitディレクトリ(リポジトリ)が作成されているか確認します。
   ```zsh
   ls -a
   ```
## コミット時のリポジトリの変化
### treeコマンドの導入
本記事ではtreeコマンドを使用して、リポジトリの内部を確認しながら進めていきます。
treeコマンドはディレクトリ構造をテキスト表示してくれるものでHomebrewからインストールを行います。
Homebrewのインストールは以下の記事を参考にさせて頂きました。

https://qiita.com/zaburo/items/29fe23c1ceb6056109fd

Homebrewのインストールが完了したらtreeをインストールします。
```zsh
$ brew install tree
```
早速treeコマンドを使ってリポジトリ内を覗いてみましょう。
```zsh
# .gitディレクトリのtreeを表示する
$ tree .git

# result
.git
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   ├── push-to-checkout.sample
│   ├── sendemail-validate.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags
```
何やらファイルがいっぱいありますね。
後でディレクトリ内を確認していくので一旦コミットの説明に入ります。

### 1回目のコミット

コミットはリポジトリにファイルの追加・変更を記録するためのコマンドです。
フローは以下の通りです。
1. ワークツリーでファイルを作成・変更します。
1. `git add ファイル名`コマンドでステージングエリアにファイルを追加します。
1. `git commit -m 'コミットメッセージ'`コマンドでステージングエリアからリポジトリにコミットします。
> `-m`オプションは必須ではありません。`-m`オプションを指定しない場合、別途コミットメッセージを入力するエディタが立ち上がります。

このフローに沿ってコミットしてみます。
先ずはワークツリーにファイルを作成します。
```zsh
$ echo first > foo
```

次に作成したファイルをステージングエリアに追加します。
```zsh
$ git add foo
```

この状態でリポジトリの中身を確認してみます。  
```zsh
$ tree .git 

# result
.git
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   ├── push-to-checkout.sample
│   ├── sendemail-validate.sample
│   └── update.sample
├── index  #追加
├── info
│   └── exclude
├── objects
│   ├── 9c  #追加
│   │   └── 59e24b8393179a5d712de4f990178df5734d99  #追加
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags
```
indexファイルと暗号のようなディレクトリとファイルが追加されている事が分かります。  
objectsディレクトリの中から確認してみます。
```zsh
# オブジェクトの中身を確認する
$ git cat-file -p 9c59e24b8393179a5d712de4f990178df5734d99 

# result
first
```
fooファイルの内容が表示されました。  
これはblob(塊)オブジェクトと呼ばれ、ファイルの中身をSHA-1というハッシュ関数で40文字の英数字に変換したものです。  
- 最初の2桁(9c) :ディレクトリ名として保存されます。
- 残り38桁(59e...) :ファイル名として保存されます。

`git cat-file -p`コマンドはオブジェクトの内容を表示するコマンドです。  
だからblobオブジェクトを指定するとファイルの内容が表示されたんですね。  

次にindexファイルの中身を確認してみます。
```zsh
# indexの中身を確認する
$ git ls-files --stage

# result
100644 9c59e24b8393179a5d712de4f990178df5734d99 0       foo
```
blobオブジェクトとステージングエリアに追加したfoo(ファイル名)が表示されています。
blobオブジェクトはファイルの中身こそ持っていましたが、元のファイル名は持っていませんでした。
これから分かる事はindexはblobオブジェクトと元のファイル名をマッピングした情報を持っているという事です。
  
今の状態からワークツリーを変更してみましょう。
```zsh
# fooファイルにsecondを追記
$ echo second >> foo
```
`git diff`を使用してワークツリーとステージングエリアの差分を表示します。
```zsh
# ワークツリーとステージングエリアの差分を表示
$ git diff

# result
diff --git a/foo b/foo
index 9c59e24..66a52ee 100644
--- a/foo
+++ b/foo
@@ -1 +1,2 @@
 first
+second
```
最終行でsecondが差分として表示されている事が分かります。
indexはワークツリーのファイル名とそのファイルの中身をハッシュ値に変換したblobオブジェクト名を持っていました。
よって`git diff`は現在のワークツリーにあるファイルとblobオブジェクトを比較する事で差分を表示している事が分かります。
　　
コミットする前にワークツリーの変更を取り消しましょう。
```zsh
# fooの変更を取り消す
$ git checkout -- foo

# fooの中身を表示する
$ cat foo

# result
first
```
`git diff`の仕組みが分かれば、何故Gitが変更を取り消せるのか想像が付くかと思います。
そうです。blobオブジェクトで内容を上書きしてしまえば元に戻りますね。

いよいよコミットしていきます。
```zsh
$ git commit -m 'fooファイルを追加'
```
コミットされました。
例の如くtreeコマンドでリポジトリ内を確認してみます。(一部省略しています)
```zsh
.git
├── objects
│   ├── 33
│   │   └── 6218e53e531a4f33067d4b038b0c621cd518de #追加
│   ├── 4a
│   │   └── 991c60a7e63047f12876efab620f21c612f478 #追加
│   ├── 9c
│   │   └── 59e24b8393179a5d712de4f990178df5734d99
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master #追加
    └── tags
```

追加されたオブジェクトを見ていきます。  
ちなみに`git cat-file`コマンドでハッシュ値を全て指定する必要はありません。
```zsh
$ git cat-file -p 336218

# result
100644 blob 9c59e24b8393179a5d712de4f990178df5734d99    foo
```
indexと似たような内容が表示されましたがハッシュ値の前に**blob**と書かれています。
これはこのハッシュ値はblobオブジェクトである事を表しています。
このオブジェクトをtreeオブジェクトと呼び、コミットした時点のファイルとディレクトリの階層構造を表すもの(スナップショット)です。

もう１つのオブジェクトも確認してみます。
```zsh
$ git cat-file -p 4a991c

# result
tree 336218e53e531a4f33067d4b038b0c621cd518de
author example-user <example_user@example.com> 1698487377 +0900
committer example-user <example_user@example.com> 1698487377 +0900

fooファイルを追加
```
各行の説明です。
- `tree` :コミット時のスナップショット(treeオブジェクト)
- `author` :コードを書いた作成者情報
- `commiter` :コミットした作成者情報
- `fooファイルを追加` :コミットメッセージ

これはcommitオブジェクトと呼ばれ、コミット時点のスナップショット、作成者情報、コミットメッセージを持っている事が分かります。
<br>
masterファイルを見ていく前にブランチとHEADについて説明します。
- ブランチ: 特定のコミットを指し示すポインタ
- HEAD: 現在作業中のブランチへのポインタ

特に設定を変えていなければ初期状態ではmasterブランチが作成されます。
これを踏まえた上でmasterファイルの中身を見ていきます。
```zsh
# masterブランチの中身を表示する
$ cat .git/refs/heads/master

# result
4a991c60a7e63047f12876efab620f21c612f478
```
上で確認したcommitオブジェクトのハッシュ値が表示されました。  
masterファイル = masterブランチであり、`4a991c...`のコミットをポインタしているという事が分かりました。
  
HEADファイルも見てみましょう。
```zsh
# HEADファイルの中身を表示する
$ cat .git/HEAD

# result
ref: refs/heads/master
```
refとは参照するという意味で、masterファイルを参照している事が分かりますね。

### 2回目のコミット
2回目のコミットを行なっていきます。
ワークツリーに新たなディレクトリとファイルを追加して`git add`します。
```zsh
# ディレクトリを作成
$ mkdir subdir

# subdirに移動
$ cd subdir/

# gooファイルを作成
$ echo second > goo

# ステージングエリアに追加
$ git add goo
```
リポジトリを確認してみましょう。
```zsh
../.git
├── objects
    ├── 33
    │   └── 6218e53e531a4f33067d4b038b0c621cd518de
    ├── 4a
    │   └── 991c60a7e63047f12876efab620f21c612f478
    ├── 9c
    │   └── 59e24b8393179a5d712de4f990178df5734d99
    ├── e0
    │   └── 19be006cf33489e2d0177a3837a2384eddebc5 #追加
    ├── info
    └── pack
```
追加されたオブジェクトを確認してみます。
```zsh
$ git cat-file -p e019be       

# result
second
```
gooファイルの中身をハッシュ化したblobオブジェクトですね。  
<br>
次にコミットして再びリポジトリを確認してみます。
```zsh
$ git commit -m 'gooファイルを追加'

$ git tree ../.git

# result
../.git
├── objects
│   ├── 2d
│   │   └── fa36e54d09d0cf551ec1c7e926e16430ca179a #追加
│   ├── 33
│   │   └── 6218e53e531a4f33067d4b038b0c621cd518de
│   ├── 4a
│   │   └── 991c60a7e63047f12876efab620f21c612f478
│   ├── 97
│   │   └── e93d75a11fdff56f98545727c5dde9a0218452 #追加
│   ├── 9b
│   │   └── f6174ad28ac301dd03c094d98ec2028ac4bbcf #追加
│   ├── 9c
│   │   └── 59e24b8393179a5d712de4f990178df5734d99
│   ├── e0
│   │   └── 19be006cf33489e2d0177a3837a2384eddebc5
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master #変更
    └── tags
```
追加された3つのオブジェクトを見ていきましょう。
```zsh
$ git cat-file -p 97e93d

# result
100644 blob e019be006cf33489e2d0177a3837a2384eddebc5    goo
```
1つ目はtreeオブジェクトでした。
  
2つ目のオブジェクトも確認してみます。
```zsh
$ git cat-file -p 2dfa36

# result
100644 blob 9c59e24b8393179a5d712de4f990178df5734d99    foo
040000 tree 97e93d75a11fdff56f98545727c5dde9a0218452    subdir
```
こちらもtreeオブジェクトの様です。
1回のコミットでtreeオブジェクトが2つ追加された事になります。
2行目にtreeオブジェクトが指定されており、追加されたもう１つのtreeオブジェクトを参照している事が分かります。
  
treeオブジェクトはコミットした時点のスナップショットを表すものでした。
仮にもう１つの`97e93d...`のtreeオブジェクトだけだった場合、subdirの階層のファイルしか分からず親ディレクトリにあるファイルが分かりません。  
そのためtreeオブジェクトを含んだtreeオブジェクトが作成され、各treeオブジェクトが下の階層のtreeオブジェクトを参照する事でスナップショットを保存する仕組みになっています。
  
commitオブジェクトで参照されるtreeオブジェクトもこちらになります。
```zsh
$ git cat-file -p 9bf617

# result
tree 2dfa36e54d09d0cf551ec1c7e926e16430ca179a
parent 4a991c60a7e63047f12876efab620f21c612f478
author aisaka-1653 <reobata1127@gmail.com> 1698500484 +0900
committer aisaka-1653 <reobata1127@gmail.com> 1698500484 +0900

gooファイルを追加
```
1回目のcommitオブジェクトには無かったparentの項目が増えています。
指定されているオブジェクトは1回目のcommitオブジェクトです。
この親コミットこそがファイルを過去の状態に戻したり、履歴を追う事ができる鍵になります。
  
今一度commitオブジェクトが持っている情報を整理します。
- コミット時のスナップショット
- 作成者情報
- コミットコメント

つまり1回目のcommitオブジェクトのスナップショットを読み込めば、その時のファイル状態を再現する事が出来ます。
又、コミットは親コミットを参照しているので、あるコミットから親コミットを辿っていけば一番最初のコミットまで履歴を追うことも出来ますよね。
<br>
試しに1個前のコミットにHEADを移動してみましょう。HEADの移動には`git checkout`コマンドを使用し`^`は1つ前のコミットを指します。
```zsh
# HEADを1つ前(親)のコミットに移動
$ git checkout HEAD^

# subdir内にあるファイルを表示
$ ls 

# result

```
1回目のコミット時には無かったgooファイルが消えて何も表示されませんね。
HEADを元に戻して2回目のコミットの説明を終了します。
```zsh
# HEADをmasterブランチに移動
$ git checkout master
```
## ブランチ操作
### ブランチの作成
ブランチとは特定のコミットを指し示すポインタのようなものでした。ブランチを分岐させる事でプロジェクト本体に影響を与えず開発を進める事が出来ます。ブランチの作成を行ってみましょう。
```zsh
# featureブランチを作成
$ git branch feature
```
このコマンドによりHEADの位置からfeatureブランチが分岐して作成されます。
リポジトリの中を確認してみます。
```zsh
refs
  ├── heads
      ├── feature
      └── master
```
先程までは無かったfeatureブランチが追加されている事が分かります。
`git branch`コマンドでブランチを確認することも出来ます。
*はHEADがどのブランチをポインタしているかを表しています。
```zsh
# ブランチを確認
$ git branch

# result
  feature
* master
```
HEADがmasterブランチを指しているという事は、ファイルを変更するとmasterブランチのファイルが変更されてしまいます。HEADをfeatureに移動させましょう。
HEADの移動は`git checkout`コマンドでしたね。
```zsh
# HEADをfeatureブランチに移動
$ git checkout feature

$ git branch

# result
* feature
  master
```
featureにHEADが移動しました。
この一連のコマンドを纏めて行うコマンドがあるので紹介しておきます。
```zsh
# featureブランチを作成してHEADを移動
$ git checkout -b feature
```

### ブランチの統合(merge)
ファイルをステージングエリアに追加していきます。
```zsh
# hooファイルを作成
$ echo third > hoo

$ git add hoo
```
リポジトリ内を確認するとhooファイルのblobオブジェクトが追加されています。
```zsh
.git
├── objects
    ├── 23
        └── 4496b1caf2c7682b8441f9b866a7e2420d9748
```

コミットします。
```zsh
$ git commit -m `hooファイルを追加`
```
リポジトリの中を確認します。
```zsh
.git
├── objects
    ├── 2b
    │   └── 90e23d612dc39eda535e83e797df79fd2457a9 #追加
    ├── a4
    │   └── ad811d916deba9e6306142ab71eda7264cd9e9 #追加
    ├── info
    └── pack
```
treeオブジェクトとcommitオブジェクトが追加されています。
ここまでは今まで学習してきた内容と同じですね。
あくまでブランチはコミットを指し示すポインタなので今回のcommitオブジェクトをポインタするだけで、masterブランチと異なるスナップショットを呼び出し分岐を実現している事が分かります。
  
続いてmasterブランチに移動してコミットしてみます。
```zsh
$ git checkout master

$ echo fourth > ioo

$ git add ioo

$ git commit -m 'iooファイルを追加'
```
これによりmasterブランチとfeatureブランチでそれぞれ1回ずつコミットした事になります。
コミット履歴を図で確認するためには`git log --graph --all`コマンドを使用します。
```zsh
$ git log --graph --all

# result
* commit 5ef7fe0f51d1a31b25d0f4f5dc149517ea2f7708 (HEAD -> master)
| Author: example-user <example-user@example.com>
| Date:   Sun Oct 29 12:54:10 2023 +0900
| 
|     iooファイルを追加
|   
| * commit 2b90e23d612dc39eda535e83e797df79fd2457a9 (feature)
|/  Author: example-user <example-user@example.com>
|   Date:   Sun Oct 29 12:16:11 2023 +0900
|   
|       hooファイルを追加
| 
* commit 9bf6174ad28ac301dd03c094d98ec2028ac4bbcf
| Author: example-user <example-user@example.com>
| Date:   Sat Oct 28 22:41:24 2023 +0900
| 
|     gooファイルを追加
| 
* commit 4a991c60a7e63047f12876efab620f21c612f478
| Author: example-user <example-user@example.com>
```
少し分かりづらいかもしれませんが、featureブランチがちゃんと分岐している事が分かります。
featureブランチの内容をmasterブランチに取り込みたい場合は、`git merge`コマンドでブランチを統合します。
mergeはHEAD側のブランチに統合されることに注意しましょう。
```zsh
# masterブランチにfeatureブランチをmerge
$ git merge feature
```
コミットメッセージを入力するエディタが表示されるかと思いますが、今回はそのまま`:wq`で保存します。
mergeが完了したら再びlogを確認してみましょう。
```zsh
$ git log --graph --all

*   commit a283b676d245b42375454626933c799c660a2ce5 (HEAD -> master)
|\  Merge: 5ef7fe0 2b90e23
| | Author: example-user <example-user@example.com>
| | Date:   Sun Oct 29 13:08:05 2023 +0900
| | 
| |     Merge branch 'feature'
| | 
| * commit 2b90e23d612dc39eda535e83e797df79fd2457a9 (feature)
| | Author: example-user <example-user@example.com>
| | Date:   Sun Oct 29 12:16:11 2023 +0900
| | 
| |     hooファイルを追加
| | 
* | commit 5ef7fe0f51d1a31b25d0f4f5dc149517ea2f7708
|/  Author: example-user <example-user@example.com>
|   Date:   Sun Oct 29 12:54:10 2023 +0900
|   
|       iooファイルを追加
| 
* commit 9bf6174ad28ac301dd03c094d98ec2028ac4bbcf
```
featureブランチがmasterブランチに統合され、新たなコミットが作成されていることが分かります。
今までコミット時にtreeオブジェクトとcommitオブジェクトが作成されていましたが、mergeした時も同様です。
  
リポジトリの中身を覗いて確認してみましょう。
```zsh
objects
    ├── 17
    │   └── 57234265e55bdbccda229ecd22e85fc18b0704
    ├── a2
    │   └── 83b676d245b42375454626933c799c660a2ce5
```
```zsh
# treeオブジェクトを確認
$ git cat-file -p 175723

# result
100644 blob 9c59e24b8393179a5d712de4f990178df5734d99    foo
100644 blob 234496b1caf2c7682b8441f9b866a7e2420d9748    hoo
100644 blob 285a4e602221896cc1cf7af42aa5e3876582a0de    ioo
040000 tree 97e93d75a11fdff56f98545727c5dde9a0218452    subdir

# commitオブジェクトを確認
$ git cat-file -p a283b6

# result
tree 1757234265e55bdbccda229ecd22e85fc18b0704
parent 5ef7fe0f51d1a31b25d0f4f5dc149517ea2f7708
parent 2b90e23d612dc39eda535e83e797df79fd2457a9
author example-user <example-user@example.com> 1698552485 +0900
committer example-user <example-user@example.com> 1698552485 +0900

Merge branch 'feature'
```
treeオブジェクトは今までと変わりませんが、commitオブジェクトに親コミットが2つ指定されています。
Gitは履歴を追うために親コミットを遡っていく必要がありました。そのためmerge元とmerge先の2つのcommitオブジェクトが参照されているんですね。

### ブランチの統合(rebase)
今回は分岐が1つなので支障はありませんが、この分岐が複数ある場合に履歴が見辛いといった問題が発生します。
先程のmergeではmasterブランチとfeatureブランチに変更が加わった為、auto-mergeと呼ばれるmerge方法でそれぞれのブランチを統合して新たなコミットを作成するものでした。
  
しかし、例えばfeatureブランチしか変更されていなければfast-forwardというmerge方法になり、masterブランチのポインタがfeatureブランチと同じ位置に移動するだけで履歴が分岐する事はありません。
つまり履歴を一直線上にする為には、featureブランチがmasterブランチの内容を取り込み、masterブランチがfast-forwardすれば良いのです。
  
それを可能にするのが`git rebase`コマンドです。
rebaseするために先ほどのmergeを取り消しましょう。
```zsh
$ git reset --hard HEAD^ 
```
このコマンドは、HEADの位置を1つ前のコミットに戻すことで、直近のマージ操作を履歴ごと取り消します。
本記事では解説しませんがmergeの取り消し方法は複数あり、その状況に応じて適切なコマンドを選択する必要があります。
mergeが取り消されているかlogを確認してみましょう。
```zsh
$ git log --graph --all

# result
* commit 5ef7fe0f51d1a31b25d0f4f5dc149517ea2f7708 (HEAD -> master)
| Author: example-user <example-user@example.com>
| Date:   Sun Oct 29 12:54:10 2023 +0900
| 
|     iooファイルを追加
|   
| * commit 2b90e23d612dc39eda535e83e797df79fd2457a9 (feature)
|/  Author: example-user <example-user@example.com>
|   Date:   Sun Oct 29 12:16:11 2023 +0900
|   
|       hooファイルを追加
| 
* commit 9bf6174ad28ac301dd03c094d98ec2028ac4bbcf
| Author: example-user <example-user@example.com>
| Date:   Sat Oct 28 22:41:24 2023 +0900
| 
|     gooファイルを追加
| 
* commit 4a991c60a7e63047f12876efab620f21c612f478
| Author: example-user <example-user@example.com>
```
ちゃんと取り消されていますね。
featureブランチに移動してmasterブランチにrebaseしていきます。
```zsh
$ git checkout feature
$ git rebase master
```
logを確認してみます。
```zsh
git log --graph --all
* commit 5b1f7ea4787b94eb9ace62d85290377a9ba3634d (HEAD -> feature)
| Author: example-user <example_user@example.com>
| Date:   Sun Oct 29 12:16:11 2023 +0900
| 
|     hooファイルを追加
| 
* commit 5ef7fe0f51d1a31b25d0f4f5dc149517ea2f7708 (master)
| Author: example-user <example_user@example.com>
| Date:   Sun Oct 29 12:54:10 2023 +0900
| 
|     iooファイルを追加
| 
* commit 9bf6174ad28ac301dd03c094d98ec2028ac4bbcf
| Author: example-user <example_user@example.com>
| Date:   Sat Oct 28 22:41:24 2023 +0900
| 
|     gooファイルを追加
| 
* commit 4a991c60a7e63047f12876efab620f21c612f478
| Author: example-user <example_user@example.com>
  Date:   Sat Oct 28 19:02:57 2023 +0900
  
      fooファイルの追加
```
masterブランチでブランチを切り、featureブランチで1回コミットしたかのように表示されています。後はmasterブランチでfast-forwardすれば完成です。
```zsh
$ git checkout master
$ git merge feature
$ git log --graph --all

# result
* commit 5b1f7ea4787b94eb9ace62d85290377a9ba3634d (HEAD -> master, feature)
| Author: example-user <example_user@example.com>
| Date:   Sun Oct 29 12:16:11 2023 +0900
| 
|     hooファイルを追加
| 
* commit 5ef7fe0f51d1a31b25d0f4f5dc149517ea2f7708
| Author: example-user <example_user@example.com>
| Date:   Sun Oct 29 12:54:10 2023 +0900
| 
|     iooファイルを追加
| 
* commit 9bf6174ad28ac301dd03c094d98ec2028ac4bbcf
| Author: example-user <example_user@example.com>
| Date:   Sat Oct 28 22:41:24 2023 +0900
| 
|     gooファイルを追加
| 
* commit 4a991c60a7e63047f12876efab620f21c612f478
| Author: example-user <example_user@example.com>
  Date:   Sat Oct 28 19:02:57 2023 +0900
  
      fooファイルの追加
```
履歴が直線になりました！

## 最後に
今回はGitの基本的なコマンドについて、リポジトリを確認しながら調査していきました。
自分にはまだ理解できていないコマンドもたくさんありますし、GitHubと連携して行うpushやpullコマンドについての理解は今後の課題です。
Gitの理解が深まった時にまた記事を作成したいと思います。