初学者向けGitコマンドハンズオン

この記事は [Git Advent Calendar 2019](https://qiita.com/advent-calendar/2019/git) 3日目の記事です。
昨日は @100 さんによる [【VRChat】継続的なクロスプラットフォーム対応](https://gitlab.com/vrc-gitcommitter/wiki/wikis/%E3%80%90VRChat%E3%80%91%E7%B6%99%E7%B6%9A%E7%9A%84%E3%81%AA%E3%82%AF%E3%83%AD%E3%82%B9%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E5%AF%BE%E5%BF%9C) でした。



# Gitコマンドハンズオン

Git初学者向けにGitハンズオンを実施しましたので、その時に作ったハンズオン資料を公開します。

Gitコマンドに慣れることが目的のハンズオンの資料ですので、Gitとは何か？といった説明はしません。ご了承ください。

お使いのPCにGitはインストール済みという前提で進めます。

文章の手順通りに進めていけば、Gitコマンドの体験ができます！



# GUIツールがあるのに、なぜGitコマンドを学習するのか？

マージ・リベース・コンフリクト・・・
こういった込み入った操作をGitコマンドだけでやるのは厳しいものがあります。

基本的には、SourceTreeのようなGUIツールを使った方が、安全だと思います。

しかし、ネットワーク設定ミス等で、SourceTreeでのクローン・プッシュ・フェッチができなくなるということが、たまにあります。

そんな時に、Gitコマンドが使えると便利ですよね！



# WindowsならGit Bashを使おう

Web界隈ではLinuxサーバーが主流ですので、DOSコマンドよりもLinuxコマンドが使える環境の方が、何かと都合がよいと思います。

`Git for Windows` をインストールしていれば、 `Git Bash` というターミナルがインストールされており、そこでLinuxコマンドが使えます。
また、カレントブランチ名が常に表示されたりと、Gitコマンドを使う上で何かと便利です。

今回のハンズオンでは、Git Bashを使う前提で進めます。



# クローン編

## 練習用のリモートリポジトリを用意しよう

まずは、練習用のリモートリポジトリを用意しましょう。

今回は私の方で、GitHubに以下のリポジトリを用意しましたので、これを利用してきます。

`https://github.com/segurvita/git-handson.git`

ご自分でリモートリポジトリをご用意できる方は、ご自身でご用意いただいたものでも問題ありません。



## 作業ディレクトリを作ろう！

まずはハンズオン用のフォルダーを作成しましょう！

ここでは、

- Windows: `D:\Git\GitHandson` 
- Mac: `~/Git/GitHandson`

とします。

フォルダーが作成できましたら、ターミナルのカレントディレクトリをそのフォルダーにしてください。



## リポジトリをクローンしてみよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/79f0d121-1d57-76f4-685c-549852f2c0a2.png)

まずは、GitHubからリポジトリをクローンしてみましょう。

以下のコマンドを実行します。

```bash
# リポジトリをクローンする
git clone https://github.com/segurvita/git-handson.git
```

GitHubの認証情報が聞かれますので、ご自身のGitHubアカウントの情報を入力してくだい。

クローンに成功すると、 `git-handson` というフォルダーが生成されますので、中に入ります。

```bash
# 移動
cd git-handson
```

今後は、この `git-handson` フォルダーを `作業ディレクトリ` と呼ぶことにします。



### 1人ハンズオンの場合は複数リポジトリをご用意ください

本記事は複数人でハンズオンを実施することを想定しています。

もし、一人で本記事の内容を実践する場合は、作業ディレクトリを2つ以上用意し、それぞれローカルリポジトリを作成してやってみてください。



## `user.name` と `user.email` を設定しよう

職場では本名で活動するけど、OSSではハンドル名義で活動したいということがあると思います。

そういう時は、ローカルリポジトリ毎に `name` と `email` を設定すればよいです。
以下のように、 `git config` コマンドを実行します。

```bash
# メールアドレスを設定する
git config user.email "メールアドレス"

# 〇〇を設定する
git config user.name "ユーザー名"
```



## ローカルブランチを作ろう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/ac3bc203-14c9-4c60-8513-8ebab1dc8db7.png)

次にローカルブランチを作りましょう

```bash
# ローカルブランチを作る
git branch feature/〇〇

# チェックアウトする
git checkout feature/〇〇
```

`〇〇` の部分は、他のユーザーとかぶらないような、好きな文字列を入力してください！



# コミット編

## 作業ディレクトリにファイルを作ろう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/ec880b85-445b-dd6b-ec2b-66afc7ebc26d.png)

作業ディレクトリに `index.html` を作成しましょう。

個人的には `nano` が便利です。（vim等、使い慣れたテキストエディターが他にあるなら、それでファイルを編集してください）

```bash
# index.htmlを作成する
nano index.html
```

nanoが起動したら、以下の内容を書きます。

```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>タイトル</title>
</head>

<body>
    本文
</body>

</html>
```

`control + X` で保存します。

以下のコマンドで中身を確認しましょう。

```bash
# index.htmlの内容を表示する
cat index.html
```

中身がちゃんと表示されれば成功です。



## ステータスを確認しよう

ステータスを確認してみましょう。

```bash
# Gitの状態を確認する
git status
```

```
On branch feature/〇〇
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        index.html

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

**ステージに追加されていないファイルがあるよ！** というメッセージが表示されました。

**ステージとはなんでしょう？**



## ファイルをステージに追加しよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/67ee85b7-b8ba-6d60-a3be-b703bf1383dd.png)

ステージというのは、コミットの候補となるファイル変更データを保管する場所です。

ファイルをステージに追加してみましょう。



```bash
# ファイルを追加する
git add .
```

`.` は、すべてのファイル変更データという意味です。

ステージへの追加ができたら、もう一度、Gitの状態を確認しましょう。

```bash
# Gitの状態を確認する
git status
```

```bash
On branch feature/〇〇
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   index.html
```

**ステージに新しいファイルがある** というメッセージになりました。

この時点ではまだ、ステージにあるだけで、コミットはされていません。



## コミットしよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/06ed179d-2b8c-f5e8-61a2-b3a96e3953a9.png)

追加したファイルをコミットしてみましょう。

コミットというのは、ステージに挙がっているファイル変更データを、ローカルブランチに反映させることです。

```bash
# 追加したファイルをコミットする
git commit -m "Added index.html"
```

```bash
[feature/〇〇 0b98e7f] Added index.html
 1 file changed, 13 insertions(+)
 create mode 100644 index.html
```

コミットができたら、もう一度、Gitの状態を確認してみます。

```bash
# Gitの状態を確認する
git status
```

```bash
On branch feature/〇〇
nothing to commit, working tree clean
```

コミットされたため、ステージが綺麗になりました！



## コミットログを確認しよう

本当にコミットできたのでしょうか？コミットログを確認してみましょう。

```bash
# コミットログを表示する
git log
```

```bash
commit 0b98e7f6ae4ac2b0aaa795ce2a0c9288c94ad767 (HEAD -> feature/〇〇)
Author: 〇〇
Date:   Sun Nov 17 00:52:17 2019 +0900

    Added index.html

commit 1834144182ea422cb89b5789ad8d8a9773a58ec7 (origin/master, origin/HEAD, master)
Author: 〇〇
Date:   Sun Nov 17 00:26:03 2019 +0900

    Initial commit
```

ちゃんとコミットされていました！



# プッシュ編

## ローカルブランチをpushしよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/013c89e0-d043-3df7-02f3-bfc813d3babc.png)

次は、 `git push` でローカルブランチを、リモートリポジトリにプッシュしてみましょう。

```bash
# ブランチをpush
git push origin feature/〇〇
```

この際、以下のようにGitHubの認証情報を聞かれるかもしれません。その時は、ユーザー名とパスワードを間違えずに入力しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/0f895022-aea1-d457-f953-7939d66d1527.png)

ここで間違えてしまうと、その間違った認証情報をOSが保存してしまって結構面倒なことになります。慎重に入力しましょう。

認証に成功すれば、ローカルブランチをリモートリポジトリにアップロードできます。

コマンド内の `origin` というのは、リモートリポジトリのブックマークです。ブックマークというのはエイリアスのようなものです。
「エイリアスってなーに？」
「つまり、リモートリポジトリに `origin` って名前を付けたんだよー」

`git push` を実行した結果、以下のようなログが表示されます。

```bash
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 410 bytes | 410.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'feature/〇〇' on GitHub by visiting:
remote:      https://github.com/segurvita/git-handson/pull/new/feature/〇〇
remote:
To https://github.com/segurvita/git-handson.git
 * [new branch]      feature/〇〇 -> feature/〇〇
```

これで、リモートリポジトリにブランチが作成されました！



## ブランチ一覧を確認しよう

ブランチの一覧を確認してみましょう。

```bash
# ブランチの一覧を表示する
git branch --all
```

```bash
  master
* feature/〇〇
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/feature/〇〇
```

`master` ブランチのほかに、自分が作成した `feature/〇〇` のブランチが表示されました。

`*` がついているのはカレントブランチという意味です。

なにやら `remotes` とついているのがいくつかありますね。これは、リモートリポジトリのブランチのように見えますが、実は微妙に違います。

たった今、ハンズオンに参加したメンバー全員がpushしたにもかかわらず、 `remotes` には自分がpushしたブランチしか表示されていません。
（1人ハンズオンの場合は、複数のローカルリポジトリからプッシュしておいてください。）

実は、ここに表示されているのは、リモートリポジトリのブランチそのものではなく、そのキャッシュなんです。

このキャッシュのことを **リモートブランチ** と呼びます。



# フェッチ編

## fetchしてみよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/1e349b07-a850-9f7d-8fb2-0f5f5b4b7219.png)

リモートブランチを更新するには、 `fetch` を実行します。

```bash
# リモートブランチを更新する
git fetch
```

再度、ブランチ一覧を確認します。

```bash
# ブランチの一覧を表示する
git branch --all
```

```bash
  master
* feature/〇〇
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/feature/〇〇
  remotes/origin/feature/□□
```

キャッシュが更新されて、他のメンバーがプッシュしたブランチも表示されましたね！



## リモートブランチをcheckoutしよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/a81f3886-4c64-65ef-5408-d1d857495da3.png)

試しに、他のメンバーが作ったブランチ `feature/□□` を、チェックアウトしてみましょう。

```bash
# リモートブランチをチェックアウトする
git checkout feature/□□
```

上記のコマンドを実行すると、以下のメッセージが表示されます。

```bash
Switched to a new branch 'feature/□□'
Branch 'feature/□□' set up to track remote branch 'feature/□□' from 'origin'.
```

どうやら、新しいローカルブランチが作られたようです。ブランチ一覧を確認してみましょう。

```bash
# ブランチの一覧を表示する
git branch --all
```

```bash
  master
  feature/〇〇
* feature/□□
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/feature/〇〇
  remotes/origin/feature/□□
```

ローカルブランチとして新たに `feature/□□` が増えました。
`*` がついているので、今度はこちらがカレントブランチになったようですね。



# 削除編

## ローカルブランチを削除しよう

せっかく作ったローカルブランチですが、次は、このローカルブランチを削除してみましょう。

```bash
# ローカルブランチを削除する
git branch --delete feature/〇〇
```

削除しようとすると、こんなエラーがでました！

```bash
error: The branch 'feature/〇〇' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature/〇〇'.
```

これは、 `feature/〇〇` がどこにもマージされていないので、「このローカルブランチを消すと、コミットした情報が消えてしまうよ！」という意味の警告です。

今回は消えても問題ないので、強制的に削除しましょう。メッセージに書いてある `-D` を使ってみます。

```bash
# ローカルブランチを強制的に削除する
git branch -D feature/〇〇
```

これで削除できたかどうか確認します。

```bash
# ブランチの一覧を表示する
git branch --all
```

```bash
  master
* feature/□□
  remotes/origin/HEAD -> origin/master
  remotes/origin/
  remotes/origin/feature/〇〇
  remotes/origin/feature/□□
```

削除できてますね！

ただ、まだリモートに `feature/〇〇` が残っています。



## リモートリポジトリのブランチを削除しよう

最後に、リモートリポジトリのブランチを削除してみましょう。

```bash
# リモートリポジトリのブランチを削除する
git push --delete origin feature/〇〇
```

削除なのになぜか `push` コマンドが登場しました。これは、 `更新` や `削除` に限らず、リモートリポジトリの内容を書き換えるときは、 `push` を使うんだと覚えてください。

それでは、削除できたかどうか確認します。

```bash
git branch --all
```

```bash
  master
* feature/□□
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/feature/□□
```

リモートブランチが削除されていますね！



# さいごに

以上でハンズオンは終了です。おつかれさまでした。

ブランチのマージやリベース等も、Gitコマンドで実施できますが、最初に述べた通り、込み入った操作はSourceTreeのようなGUIツールでやった方が安全だと思います。
それでも、気になった方は、是非Gitコマンドでもやってみてください！

本記事作成にあたり、以下のページを参考にしました。ありがとうございました。

- [Gitのリモートブランチを削除するまとめ](https://qiita.com/yuu_ta/items/519ea47ac2c1ded032d9)


[Git Advent Calendar 2019](https://qiita.com/advent-calendar/2019/git) の明日の記事は @ko-he-8 さんによる [[Git初心者向け] GithubやGitlabでcommit時のメールアドレスは大切なんだという話。](https://qiita.com/ko-he-8/items/519c72c6eb4daccba871) です。