【図解解説】これ1本でGitをマスターできるチュートリアル！【完全版】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/484cfd2f-8d03-a646-9c76-64c8051fcddd.png)


# はじめに

こんにちは、Watanabe Jin(@Sicut_study)です。

今回は記事1本で初心者が必要な知識を全て学べるGitチュートリアルを紹介していきます。
世の中にはたくさんのGitに関する教材があります。しかし、真に良いと思える教材はありません。

もちろん私も4年前はGitという言葉を知らない状態から、書籍などで学習をしました。
しかし、書籍で知識を得たとしても実際にコマンドを使って実践的に学んだわけではなかったので**ほとんど身になりませんでした。**

私が思う世の中にあるGitの教材のイケてない点は2つです。
　

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/72860679-c793-9698-9c8c-62c3cbc3af2e.png)

結局ほとんどの人が、教材ではなく実際に使ってみて使えるようになっているはずです。
書籍でやったことを全部ちゃんとできるようになった人はいないと考えています。

実際に利用するコマンドは限られている、たまに使うコマンドを紹介しとしても「この記事1本」で説明することができると思って完全版の記事を書くことにしました。

<font color="red">**このハンズオンを最後まで行うことで、現場で問題なく利用できるスキルを身につけることが可能です。**</font>

# 動画で学びたい方へ

こちらの記事をテキストにより詳細に解説している動画を投稿しています。
初心者の方はぜひこちらをご活用ください。

<iframe width="560" height="315" src="https://www.youtube.com/embed/V7WAxif7yT4?si=hmO4GRBZOCK0iIIE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# おすすめ記事
　

他にも多くの1本で学べる完全版ハンズオンを投稿しています。よければご覧ください。

　

https://qiita.com/Sicut_study/items/340022c2a7bc05b15587

https://qiita.com/Sicut_study/items/4f301d000ecee98e78c9

https://qiita.com/Sicut_study/items/d520f9a858506b81e874

# 1. Gitとは？

Gitとは世界で最も人気のある**バージョン管理システム**です。
バージョン管理システムとは、コードに加えられた変更を**リポジトリ**と言われるデータベースにバージョンとして記録するシステムです。

変更履歴を管理して見られるようにすることで、どのような変更をなぜ加えたのかを確認が可能です。履歴をみることで「誰が」「どのような変更を」「なぜ加えたのか」を確認することができます。
　

**バージョン管理をしていないとどうなるのでしょうか？**
　
 　
 バージョン管理システムがないと、コードがまとまったフォルダをまるまるコピーして残しておく必要があります。
 こんなファイルみたことないですか？？👇

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2016149d-f4e0-2322-6430-e15b9bc48c09.png)



バージョン管理には「中央集中型システム」と「分散型システム」に分類が可能です。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/1d11a53a-83d3-126f-dc05-2a43fec51d8c.png)

中央集中型システムには、`Subversion`や`Concurrent Version System`があります。
中央集中型では中央のサーバーに接続して最新のコードを取得します。

**欠点は単一障害点があります。**　もしサーバーがオフラインになってしまったとするとバージョン管理ができくなってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/70503d6d-2e5e-6b2f-0d6f-a07cbc647d97.png)

その欠点をカバーしたのが「分散型システム」です。
分散型システムには`Git`や`Mercurial`などがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/565ad25a-b11d-794f-eee6-bbaf71bb1183.png)

ユーザーそれぞれにリポジトリをもつため、他のリポジトリと同期することができます。
中央に主となるサーバーがないためオフラインになる心配もありません。


　
 この中でも特に**Git**は世界中で最も利用されるバージョン管理システムとなります。
 あなたがソフトウェアエンジニアを目指すのであれば、必須のスキルになります。
　

 ハンズオンを全て行うことで実際に現場で利用するGitの知識を網羅することが可能です。

 # 3. GitHubとは？

 GitとGitHubは同じように扱われることもありますが、異なるものです。

 GitHubはクラウド上でGitを使ってバージョン管理できるサービスのことを表します。

https://github.com
 
 その他にもWebサービスならではのプロジェクト管理の機能を利用することも可能です。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2bb51e6f-fcb4-377a-4082-77cb961ebadd.png)

「プルリクエスト」などはGitHubで利用できる一つの機能となります。

 # 2. Gitのインストール

 ハンズオンを行う前にGitをインストールしましょう。
 それぞれのOSにあった方法(Windows, Mac)でインストールを行ってください。

 https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-Git%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

 ここではLinuxでのインストールを紹介します。

 ```
 $ apt update
 $ apt install git
 
❯ git version
git version 2.43.0
```

`git version`とターミナルに入力してバージョンが表示されれば完了です。

# 3. Gitの初期設定

まずはGitとGitHubの初期設定を行っていきます。
バージョン管理には「誰が」「いつ」「どのような変更をしたか」を記録するためにユーザー情報を付与しています。
その情報を利用前に設定する必要があります。

```
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
```

ここでは名前とメールアドレスを設定しました。`global`とすることでPCのどこでGitを利用してもこのユーザー情報を付与することができます。

次にGitHubにあるクラウド上のリポジトリ(リモートリポジトリ)と、手元のリポジトリ(ローカルリポジトリ)を通信できるような設定をおこないます。

ここでは**SSH接続**という方法で通信を行うことで、普段であれば必要なユーザー名、パスワード入力をしないでも簡単にローカルリポジトリとリモートリポジトリを同期できるようにしましょう。

　

 まずはSSHで必要となる`公開鍵`と`秘密鍵`を設定します。
 公開鍵と秘密鍵はシンデレラのガラスの靴のような関係があります。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/7501a7d3-1123-38c1-8e99-cac8b2de39af.png)

ガラスの靴(公開鍵)をGitHubに設定します。
そしてGitHubはアクセスが合ったときに、そのガラスの靴をはける人だけをシンデレラ(正しいユーザー)と認めてリクエストを許可します。

秘密鍵と公開鍵のペアが正しくない場合はリクエストが通らないようになっています。

まずは公開鍵と秘密鍵のペアを作成しましょう

```
$ cd ~/.ssh
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/(username)/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
```

`Enterキー`を3回押せば公開鍵と秘密鍵が作成できます。

```
❯ ls ~/.ssh
authorized_keys  id_rsa  id_rsa.pub 
```

`id_rsa`が秘密鍵、`id_rsa.pub`が公開鍵にあたります。

公開鍵の内容をクリップボードにコピーします。

```
$ pbcopy < ~/.ssh/id_rsa.pub (Mac)
$ clip < ~/.ssh/id_rsa.pub (Windows)
$ cat ~/.ssh/id_rsa.pub | xsel --clipboard --input (Linux)
```

次に[GitHub](https://github.com)にアクセスします。
アカウントがまだない方は作成をしてください。

右上のアイコンをクリックするとメニューが開くので、**Settings**をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/9b921dd6-66cb-6bd5-20a7-93b230b7703c.png)

左メニューの「SSH and GPCG Keys」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/a3dc8dd9-855f-b475-3077-edfc8dfa70cb.png)

「New SSH Key」をクリックして

Title : handson (なんでもよい)
Key : クリップボードの内容を貼り付け (Ctrl+v)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/88154159-772c-9aa9-daf7-2ddd5ff282d0.png)

「Add SSH Key」をクリックしたら設定完了です。

```
$ ssh -T git@github.com
Hi jinwatanabe! You've successfully authenticated, but GitHub does not provide shell access.
```

このコマンドを実行してレスポンスが返ってきたら成功です。

# 4. リポジトリを作ろう

まずはローカルリポジトリを作りましょう。
この操作はGitを使ってプロジェクトを管理する場合に最初に必ず行う必要があります。

以下のコマンドを実行すればリポジトリを作成することが可能です。

```
$ mkdir git_handson
$ cd git_handson
$ git init
Initialized empty Git repository in /home/jinwatanabe/workspace/qiit/git_handson/.git/
```

リポジトリにすることで以降出てくる`git add`や`git commit`などのコマンドが利用できるようになります。

```
$ ls -la

合計 12
drwxrwxr-x 3 jinwatanabe jinwatanabe 4096  9月 28 11:03 .
drwxrwxr-x 3 jinwatanabe jinwatanabe 4096  9月 28 11:03 ..
drwxrwxr-x 7 jinwatanabe jinwatanabe 4096  9月 28 11:03 .git
```

`.git`というディレクトリが作られました。
これは隠しファイルとなっているので画面から見ると表示されません

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/caacc9e0-142a-475a-7531-321c788acc05.png)

この`.git`にプロジェクトのバージョン管理に関する情報が含まれています。
試しに.gitを削除してみましょう

```
rm -rf .git

❯ git status
fatal: not a git repository (or any of the parent directories): .git
```

`git status`を実行するとgitレポジトリではないですと言われました。(git statusについては後で説明)

このあとのハンズオンのために再度リポジトリを作成しておきましょう

```
$ git init
```

# 5. Gitワークフロー

ここからはGitでプロジェクトのバージョン管理をするときの一般的なフローを紹介してい行きます。
　

あなたは開発しているシステムに脆弱性がみつかり、ハッキングをされてしまっている状況だとします。
そこでコードを修正してリポジトリに反映させようとします。ここでリポジトリに対して**永続的に保存**するために行うのが<font color="red">**コミット**</font>(Commit)です。
　
 
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/bad9a26a-2283-760b-6200-f626d8e8fdbb.png)

　
コミットをすることで、リポジトリに変更の履歴が残ります。
しかし、一部ファイルは履歴に含めたくない(commitしたくない)と考えることもあります。

　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/7981c687-a087-4767-331f-4a853364c0fe.png)

 
そこでGitには**ステージング**(インデックス)というコミットしたファイルを仮でおいておく場所が存在します。

  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/4db7aad8-6e2c-c95d-afe9-de9200c156b1.png)

 
ステージングに追加するファイルを<font color="red">**addコマンド**</font>で選択することによって、コミットに履歴に追加したいファイルだけを含めることが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ac372330-084a-0e61-befc-e45b9b14be0f.png)

もしステージングに不要なファイルが含めてしまった場合は、ステージングから特定のファイルを外すことも可能です。

ここまでの流れはざっくりこんな感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/e175e68e-4c56-64ba-3ac3-d32e12af9a98.png)


コミットをすることによって、以下の情報が変更に対して付与されるため履歴を管理できるのです。

 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/a36bc982-9389-2d54-5bd9-95bc66d78ce2.png)

　
ローカルリポジトリにコミットができたら、次にGitHubにある**リモートリポジトリ**に変更を反映します。
リモートリポジトリに反映することでクラウドから他のメンバーは最新のコードを取得することが可能です。

 　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/cddd4126-23c0-d9a8-8df8-4a0eb2fdd6f2.png)

ここまでの流れをgitコマンドで実行すると以下のようになります。

```
$ git add [ファイル名]
$ git commit -m "どのような変更をしたかのメッセージ"
$ git push

# リモートリポジトリの変更を取得する場合
$ git pull
```

それでは実際にやってみましょう。
現在ローカルのリポジトリはあるので、まずはリモートリポジトリをGitHubで作成しましょう。
[GitHub](https://github.com)にアクセスして、アイコンをクリックしてメニューを開き、「Your Repository」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/226642e7-4298-cb34-49ce-2fca4fd3f398.png)

右上の「New」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/68b8c651-fb6e-c889-6529-3df775fdb2aa.png)

Repository nameに「gith_full_course」と入力して「Create Repository」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/06121aaa-4a09-7160-1617-60977a7313b5.png)

これでリモートリポジトリが完成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/811e75ed-937c-3cc6-6b5c-fbf7186c04e8.png)

次にローカルリポジトリとリモートリポジトリを同期させる設定をコマンドで実行します。
「Quick setup」の選択している2行のコマンドを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/b1e3890c-aa6e-ad3c-5280-375f51e10281.png)


```
$ git branch -M main
$ git remote add origin git@github.com:jinwatanabe/git_full_course.git
```

`git branch -M main`はmainという名前のブランチを作成しています。こちらは後ほど説明します。
最後のコマンドで実行した場所のリポジトリとリモートリポジトリを紐付けています。

それではまずはステージングエリアに追加するところをやっていきます。
VSCodeで作成したリポジトリを開いてください。

そして`index.js`というファイルを作ります。

```
$ touch index.js
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/fc3512b9-02a6-b703-7f79-debb99a7b313.png)

今回は適当なコードを書いてみます。以下をコピペして貼り付けてください。

```js:index.js
console.log("Hello Git");
```

それでは、`git status`コマンドで状態を確認してみましょう。

```
$ git status

ブランチ main

No commits yet

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index.js

nothing added to commit but untracked files present (use "git add" to track)
```

`git status`コマンドを使うと、のコマンドを実行すると、どの変更がステージング済みでどの変更がまだステージングされていないのか、どのファイルが Git の追跡対象外になっているのかが表示されます。

この場合、index.jsがまだステージングに追加されていないことがわかります。
それではステージングに変更を追加しましょう。

```
$ git add index.js
$ git status

ブランチ main

No commits yet

コミット予定の変更点:
  (use "git rm --cached <file>..." to unstage)
	new file:   index.js
```

index.jsがコミットされたことがわかります。
それでは複数ファイルを次はステージングに上げてみましょう

```
$ touch index2.js
$ touch index3.js
```

```js:index2.js
console.log("Hello Git2");
```

```js:index3.js
console.log("Hello Git3");
```

```
$ git status
ブランチ main

No commits yet

コミット予定の変更点:
  (use "git rm --cached <file>..." to unstage)
	new file:   index.js

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index2.js
	index3.js
```

それではindex2.jsとindex3.jsをステージングに追加します。
1つずつ丁寧に追加してもいいですが複数ファイルを追加するときはもっと便利な追加の仕方があります。

```
$ git add index2.js index3.js

or 

$ git add .
```

git addに続いて複数ファイルを指定するか、`.`を使うことではディレクトリ配下のステージング追加されていないファイルをすべて追加することが可能です。

`git add .`が実際には多く利用されます。

それでは、次にコミットして履歴を追加しましょう

```
$ git commit -m "初めてのコミット"
[main (root-commit) f073dd5] 初めてのコミット
 3 files changed, 2 insertions(+)
 create mode 100644 index.js
 create mode 100644 index2.js
 create mode 100644 index3.js

git_handson on  main via  v22.4.0 

$ git status
ブランチ main
nothing to commit, working tree clean
```

コミットが終わることで、git statusから表示がなくなりました。

それでは最後にローカルリポジトリとリモートリポジトリを同期させます。

```
$ git push origin main

Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 363 bytes | 363.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:jinwatanabe/git_full_course.git
 * [new branch]      main -> main
```

`origin main`はオリジンがリモートリポジトリのことを指しており、リモートリポジトリのmainブランチに対して、ローカルの変更を反映させるというコマンドです。
異なるブランチにpushする場合はmainの部分が変わります (あとで説明します)

先ほど作成したGitHubのリポジトリをみるとローカルリポジトリの内容が同期していることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/0d7b9562-279f-e704-c850-077f00ccdac7.png)

# 6. コミットは細かくする

コミットはステージングにある変更を履歴に含めますが、なるべく細かくステージングに入れてコミットすることをおすすめします。
　

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/e82fdfa8-8fc2-1b9d-0153-4f934a99385f.png)


 細かいコミットにしておけばピンポイントで取り消したいコミットをなくすことが可能です。(revert)
 もし全部のコミットが1つにまとまっている場合、修正の一部だけを取り消すというのが難しくなります。

バグ修正中にタイポを見つけたら同じコミットに含めるのではなく、それぞれ別にしてメッセージも意味のあるものにするのが大切です。

コミットメッセージはそれぞれのコミットが何を行ったのか伝えるためにも大切です。

# 7. ステージングの変更を消す

index1.jsの内容を少し変更します。

```js:index1.js
console.log("change");
```

変更を確認してみましょう。`git diff`が使えます。

```
$ git status
ブランチ main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   index.js

$ git diff
diff --git a/index.js b/index.js
index bb8ec33..5e022a9 100644
--- a/index.js
+++ b/index.js
@@ -1 +1 @@
-console.log("Hello Git");
+console.log("change");
```

履歴に保存されているindex1.jsとの差分を表示してくれます。
それではステージングに持っていきます。

```
$ git add .
$ git status

ブランチ main
コミット予定の変更点:
  (use "git restore --staged <file>..." to unstage)
	modified:   index.js
```

index.jsの修正が間違えていたので、ステージングから戻してみます。

```
$ git resotre --staged index1.js
ブランチ main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   index.js
```

`git restore --staged`で戻すことができます。

では、index1.jsに加えた変更ももとに戻したいと思います。

```
$ git checkout index.js
```

`checkout`することによって修正ももとに戻ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2f44ebaa-4da6-ab1d-72d0-d7964a34afb9.png)

では新しいファイルをつくりましょう

```
$ touch index4.js
$ git status

ブランチ main
追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index4.js

nothing added to commit but untracked files present (use "git add" to track)
```

ここでファイルを取り消すために`checkout`してみましょう

```
$ git checkout index4.js
$ git status

ブランチ main
追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	index4.js
```

新規追加されたファイルは`checkout`ではもとに戻せません。
ファイルを削除すると戻すことができます

```
$ rm -rf index4.js
$ git status

ブランチ main
nothing to commit, working tree clean
```

ちなみにcheckoutはaddと同じく`.`や複数ファイル選択もできます。

# 8. 特定のファイルやでディレクトリをgitの管理外にする

次に特定のファイルやディレクトリをgitの管理対象外にする`git rm`コマンドを紹介します。

まずは1つ秘密の情報が載っているファイルをcommitします。

```
$ touch secret.txt
```

```txt:secret
秘密の情報
````


```
$ git add .
git_handson on  main [+] via  v22.4.0 

$ git commit -m "色々開発した"
[main 9f13ec2] 色々開発した
 2 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 secret.txt
$ git push origin main
```

GitHubのリポジトリにsecret.txtが追加されました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/c94c1614-c599-c08d-5302-349d606bbe82.png)

しかし気づきます。このファイルはGitHubにアップロードしてはいけないファイルだということに。
そこで`secret.txt`をgitの管理外に戻したいと思います。

```
$ git rm --cached secret.txt 
❯ git status
ブランチ main
コミット予定の変更点:
  (use "git restore --staged <file>..." to unstage)
	deleted:    secret.txt

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)
	secret.txt
````

`git rm --cached [ファイル名]`でgitの対象外にできます。
もしファイルも削除したい場合は`git rm [ファイル名]`で対象から外してファイル削除まで可能です。

いまのままでは追跡されていないファイルに`secret.txt`があり、`add`してしまう可能性がありますので、ここにも表示されないようにgitから完全に対象にならないよう設定してきます。

そこで利用するのが`.gitignore`です。

```
$ touch .gitignore
```

このファイルにgitの管理対象にしたいファイルやディレクトリを選択することができます

```.gitignore
secret.txt
```

VSCodeをみるとsecret.txtのファイルが削除されたことに成ります。
これはgitで管理から削除されてなくなったことを表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/b23abefd-7798-3ebd-31b2-5440def3a87a.png)

では、pushまでやってきます。

```
$ git add . // .gitingnoreファイルをステージングへ
$ git commit -m "秘密のファイルを削除"
$ git push origin main
```

GitHubからsecret.txtが消えました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/893c2247-ec6c-752c-79d1-33274fc634f4.png)

:::note warn
ここで注意が必要なのは一度Pushしてしまうとクラウドに履歴が残ってしまうため、完全に削除することは不可能です。シークレットな情報をクラウドにあげてしまうと、誰かに見つかってしまった場合悪用されることに繋がります。AWSのシークレットキーが流出した場合はAWSのリソースを気づかないうちに使われて高額請求につながることがあります。秘密の情報は.gitignoreに追加するのを忘れないでください。
:::

それでは次にディレクトリごとgitの管理外に設定したいと思います。

```
$ mkdir log
$ touch log/log1.txt
$ touch log/log2.txt
```

そしてGitHubにpushします。

```
$ git add .
$ git commit -m "logを追加"
$ git push origin main
```

ログがGitHubに追加されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/7608a327-5bae-4ee3-571e-a95e0bf62531.png)

しかし思いました。ログを管理する必要はないのでバージョン管理から外したい。
そこで`log`ディレクトリをそのまま管理外にしてみます。

```
$ git rm --cached log
fatal: not removing 'log' recursively without -r
```

しかし上手く行きません。ディレクトリの中身も含めてgitの対象外にする場合は`-r`をつける必要があります。

```
$ git rm --cached -r log
rm 'log/log1.txt'
rm 'log/log2.txt'
```

上手く行きました。では`.gitignore`に`log`ディレクトリを設定しておきましょう

```.gitignore
secret.txt
log
```

logディレクトリが薄くグレーアウトしています。これはgitの管理から外れていることを意味しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ffe777de-534d-d5fb-13c5-1e8690e40914.png)

それでは現在の状態をクラウドに反映してlogディレクトリを消しましょう

```
$ git add .
$ git commit -m "logを削除"
$ git push origin main
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2e3e16ce-0238-cd48-df3d-9820be1c5e6f.png)

GitHubからも消すことができました。

# 9. 履歴を確認する

時々過去にどんなコミットを行ったのか見たくなることがあります。
私達はこのハンズオンで最初にどんなコミットを行ったか覚えていますか？

そこで利用できるのが`git log`コマンドです。

```
$ git log
commit 536c9467b8a1781cd7bfd00bc760909841923593 (HEAD -> main, origin/main)
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 18:18:29 2024 +0900

    logを消した

commit 607cbb242a63cb32fe2b26ba49b5a607e18d8a12
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 18:14:14 2024 +0900

    ログ追加

commit 7c25e8c12330e7e53f6f7ba75d7ebbbc9ecdde7b
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 18:09:44 2024 +0900

    秘密のファイルを削除

commit 9f13ec22333fb03aa593ca1582012a40241755d9
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 17:58:01 2024 +0900

    色々開発した
```

このように過去のコミットを一覧で見ることが可能です。(:qで戻ることができます。jで上、kで下を表示します)
詳細を見る場合は`git log -p [コミットID]`でみれます。

```
$ git log -p 9f13ec22333fb03aa593ca1582012a40241755d9

commit 9f13ec22333fb03aa593ca1582012a40241755d9
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 17:58:01 2024 +0900

    色々開発した

diff --git a/index.js b/index.js
index bb8ec33..5e022a9 100644
--- a/index.js
+++ b/index.js
@@ -1 +1 @@
-console.log("Hello Git");
+console.log("change");
diff --git a/secret.txt b/secret.txt
new file mode 100644
index 0000000..ccae75b
--- /dev/null
```

私はgitコマンドとは別に`tig`というライブラリをいれています。
このライブラリを入れて`tig `と打つだけで、リポジトリのログを簡単に見ることができるのでおすすめです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/57dbb9e6-7b75-ab05-6a2e-3e5c29b8db3a.png)

# 10. コンフリクトの解消

リモートリポジトリに変更を加えられるのは私だけでなくチームのメンバーもできます。
今回はチームのメンバーの誰かが修正をしたとして、GitHubの画面上でコード編集をしてみます。

`index1.js`を開いて、右上の鉛筆マークをクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/45deb24f-f213-aa4c-81c6-3dee9615db2b.png)

```index.js
function greet() {
  console.log("Hello from the main branch!");
}
```

このように変更して、右上の緑のボタン「Commit changes...」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/84eb2be0-7ae4-33d0-a330-ecc233799384.png)

Commit messageに「チームの誰かが変更」としてCommit changesボタンを押します。
ここはローカルでgitコマンドを叩いているのと変わりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/23c4419f-8ba6-90d3-2162-96bc21b85768.png)

この操作はチームの誰かがやっていると仮定して、私達も`index.js`に修正をしていたとします。

```js:index.js
function greet() {
  console.log("Hello from the local branch!");
}
```

それでは私達の修正をリモートリポジトリに反映したいと思います。

```
$ git add .
$ git commit -m "私達の修正"
$ git push origin main

To github.com:jinwatanabe/git_full_course.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:jinwatanabe/git_full_course.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```

`git push`でエラーが発生しました。
リモートリポジトリが私達の手元にあるものとバージョンが変わったので、まずはリモートリポジトリの最新バージョンを手元に取得してくれと言われました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/9c08237c-6b86-e687-d2e8-792a7a9bd72f.png)

そこでまずは`pull`コマンドでリモートリポジトリの最新のコードを手元に持ってきます。

```
$ git pull -r origin main
From github.com:jinwatanabe/git_full_course
 * branch            main       -> FETCH_HEAD
Auto-merging index.js
CONFLICT (content): Merge conflict in index.js
error: 9e3ead0を適用できませんでした... 私達の修正
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 9e3ead0... 私達の修正
```

すると`CONFLICT (content): Merge conflict in index.js`という文章が出ました。
これこそが**コンフリクト**という現象です。VSCodeで`index.js`をみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/6fae6758-849b-4c3c-e144-573784a4e3f4.png)

誰かが修正したコードと私が修正したコードがかぶってしまっているために、gitではどちらが正しい修正なのか判断ができずにコンフリクトが発生しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/8c669c1c-0a28-7933-0f57-e90ac19e30a1.png)

この場合手元でコンフリクトの解消をおこな必要があります。
正しいコードを今回は私達のコードの方として、リモートのほうのコードを消しましょう

「Accept Current Change」をクリックすることで私達の修正を採用できます。

それではリモートリポジトリにpushまで行いましょう。

```
$ git add .
$ git commit -m "修正"

$ git status
interactive rebase in progress; onto 8e508ca
Last command done (1 command done):
   pick 34782ce test
No commands remaining.
You are currently editing a commit while rebasing branch 'main' on '8e508ca'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working tree clean
```

git statusをみると`You are currently editing a commit while rebasing branch 'main' on '8e508ca'.`とでています。

rebaseに関しては後で説明しますのでここは以下のコマンドでrebaseを終わらせます

```
$ git rebase --continue
$ git push origin main
```

無事修正を反映することができました！

# 11. ブランチを作ってプルリクを作ろう

gitにはブランチという履歴を分岐する機能があります。
これまでにできているmainブランチというのが中心のブランチでそこから派生してブランチを作ることになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/d45b0a9d-9efa-d378-abf9-2e988b795a2e.png)

例えば、コミットCの地点で`featureブランチ`を作るとします。
ここのブランチで機能Aの開発をしたとします。(コミットD, コミットE)

mainブランチでは別の作業が行われていて、コミットF、コミットGが作られました。
このときfeatureブランチの機能A開発で大きなバグが起きたとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/57d000ac-76f1-1c35-013b-8039054593d7.png)

しかし、ブランチが別れていればmainブランチに影響は起きません。リリースも問題なくできます。
最終的にはmainブランチに、featureブランチの内容をマージ(合わせる)ことで機能Aをmainブランチに取り込むことが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ba89390b-3c28-657c-a872-d1d214f0c8fb.png)



それでは実際にブランチを作成してみましょう。

```
$ git branch
* main

$ git branch -M feature
$ git branch
* feature
```

これでfeatureブランチをはやして見ているブランチを切り替えることができました
ちなみにmainブランチに戻りたい場合は、`git switch main`で可能です。

それではfeatureブランチで追加の開発を行います。

```js:index.js
function greet() {
  console.log("Hello from the main branch!");
}

greet();
```

関数を呼び出すようにしてみました。
それではこのブランチの変更をGitHubに反映させましょう

```
$ git add .
$ git commit -m "関数を呼び出した"
$ git push origin feature
```

ここでのポイントはpush時にfeatureブランチに対してpushしていることです。
こうすることでmainブランチに影響を与えずに開発ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/5318310c-70b9-3bab-e731-afd99a13b418.png)

mainをクリックするとfeatureが表示されるようになりました。
ではこの修正をmainブランチに**マージ**するためにプルリクエストを作ります。

「Compare & pull request」をクリックします。
プルリクエストのタイトルに概要を書きます。ここでは「関数の呼び出しを追加しました」とします。
その下のフォームに実装の詳細などを本来書いておきますが、省略します。

もう一つポイントは、その上にある**main←feature**です。
これはfeatureブランチをmainブランチに取り込むことを表しています。

プルリクを作成するために「Create pull request」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/3d236141-edd0-0089-a474-f122ed934a59.png)


そしたら「Merge pull request」→「Confirm Merge」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/9da29c0f-f029-6af7-a5a8-b3f356f93b7c.png)

もうブランチは不要なので「Delete branch」をクリックして消しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/2e607fb0-0e34-197f-584d-0b4a6982e006.png)

それでは実際にmainに変更が取り込まれたかを確認します。

```
$ git switch main
$ git pull -r 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 (from 0)
Unpacking objects: 100% (1/1), 961 bytes | 961.00 KiB/s, done.
From github.com:jinwatanabe/git_full_course
   ae5b6e4..b999746  main       -> origin/main
Updating ae5b6e4..b999746
Fast-forward
 index.js | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
```

無事反映することができました。
プルリクを活用することで大人数での開発も簡単に行うことが可能です。
またブランチをあえて作らない開発方式も存在しており、それを「トランクベース開発」と呼びます。

# 12. コミットをなかったことにする

ここでとある問題が発生して、先程マージしたコミットを取り消さないといけなくなりました。
コミットを取り消すものとして**revert**と**reset**の2つがあります。

## revert

リバートは対象のコミットを取り消すコミットを作成することでなかったことにします。
取り消したいコミット自体はちゃんと残り続けるのがポイントです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/a950c8ea-1137-4fac-44db-330a1cbdf9c9.png)

実行のコマンドを紹介します。

```
$ git revert [コミットID]
```

## reset

resetはコミット自体をなかったことにします。履歴が消えてしまうため1度消してしまうと後戻りができません。

```
$ git reset --hard [コミットID]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/9fa903e4-cbf4-0a6b-a9aa-88d082294091.png)

## 前回のコミットを取り消す

取り消し方には2通りありますが、基本的には`revert`を利用するようにしましょう

まずは適当なコミットを作成します。

```js:index.js
function greet() {
  console.log("Hello from the main branch!");
}

greet();
greet();
```

```
$ git add .
$ git commit -m "不要なコミット"


$ git log
commit 1638301f2d59a47c256f53641064fbfe4454e9d9 (HEAD -> main)
Author: jinwatanabe <jin.watanabe.6g@gmail.com>
Date:   Sat Sep 28 19:38:28 2024 +0900

    不要なコミット

$ git revert [git logでみた最新のコミットID]
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/777ff593-0879-04ed-f84a-2bca3c6168d6.png)

すると、直前のコミットを取り消すコミットのメッセージをどうするかを聞かれるので、
「Ctrl + X」で抜けます。(nanoエディタが開きます)

取り消しのコミットの詳細をみてみると、great()をなくすような変更が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/e929a325-dd8a-f3d4-aa2c-3fa09a27f0bc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/23413dd6-2be6-5b2e-2794-bfeeca467c7b.png)

コードもしっかり戻っています。

# 13. マージとリベース

先程マージの挙動を解説しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ed9178c6-7306-7710-3800-bdc0c020d984.png)

これに似た仕組みに**リベース**があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/c7f19981-5f66-41ad-a373-f65d83703d57.png)

このようなブランチの状況だった時に、`featureブランチ`で`git rebase main`とすると以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/ffad6389-a5fb-7592-d915-78bc9de4be74.png)

ここでmainブランチとfeatureブランチがコンフリクトを起こした場合は、ステージングに修正を反映させたら、**コミットではなく**`git rebase --continue`を実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/17b643a8-5c68-7769-1315-2d7f91aac5f0.png)

`merge`と`rebase`の違いは、コミットを作るか作らないかの差があります。
mergeであれば、2つを合わせるためのコミットをわざわざ作成していました。(作成したプルリクにcommitメッセージを書いていたのはそのためです)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/57821198-4f2b-4fa0-2ea1-665382ebfdeb.png)

`git pull -r`というのは、`git pull`をして持ってきた最新の情報を`rebase`でブランチに取り込むということを表していました。

# おわりに

今回は業務でよく使うコマンドから、使う回数は少ないけど必ず利用するコマンドを一通り紹介しました。
この記事をすべて行って理解することができれば仕事は安心して行うことが可能です。

使いながら1回理解しておいて、Gitを使う中で忘れてしまった時にこの記事に戻ってきていただけると良いかなと思います。

より詳細に説明した動画も用意していますのでご覧ください！



ここまで読んでいただけた方はいいねとストックよろしくお願いします。
@Sicut_study をフォローいただけるととてもうれしく思います。

また明日の記事でお会いしましょう！

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？

興味のある方は、ぜひホームページからお気軽にご連絡ください！
▼▼▼

https://projisou.jp