gitについて自分のにわか知識を撲滅したい その1 基本編

# gitについて自分のにわか知識を撲滅したい 基本編

こちらは[ITRC Advent Calendar 2019](https://adventar.org/calendars/4759)の13日目の記事です。
2日前の人: [トラコンの感想](https://gamou-tatsumi.com/2019/12/11/icstsc-2019-impressions/)
前の人: 限定公開でした。
次の人: [VisualStudioCode 便利なプラグインをまとめてみた](https://qiita.com/Possive/items/1d764ad631e42555d6ef)

## 目的

自分のにわか知識を撲滅したく調べてみました。
今回はgitの歴史や仕組み、自分がなんとなく使っていた基本的なコマンドなどの用語理解編です。

## 目次

- gitとは
- バージョン管理とは
- リポジトリとは
- ローカルバージョン管理システム
- 集中バージョン管理システム
- 分散バージョン管理システム
- Gitを使用する上で最低限必要な用語
- ローカルリポジトリとリモートリポジトリ
- gitサーバとは
- なんとなく使っていたコマンド達
- commitとpushについて
- cloneについて
- pullについて
- コマンドの流れ
- 参照

## gitとは

- 分散バージョン管理システム
- スナップショットでファイルを保存

## バージョン管理システムとは

ファイルを以前のバージョンに戻したり、変更履歴を保存するためや誰がいつファイルを変更したのか確認のためしたりなどを行え、
かつ、それらをリポジトリで管理するのがバージョン管理システムです。

<details><summary>参考にした文章</summary><div>

>「バージョン管理」とは何でしょうか。また、なぜそれを気にする必要があるのでしょうか。 バージョン管理とは、一つのファイルやファイルの集合に対して時間とともに加えられていく変更を記録するシステムで、後で特定バージョンを呼び出すことができるようにするためのものです。 本書の例では、バージョン管理されるファイルとしてソフトウェアのソースコードを用いていますが、実際にはコンピューター上のあらゆる種類のファイルをバージョン管理のもとに置くことができます。
もしあなたがグラフィックス・デザイナーやウェブ・デザイナーで、画像やレイアウトの全てのバージョンを保存しておきたいとすると（きっとそうしたいですよね）、バージョン管理システム（VCS）を使うというのはいい考えです。 VCSを使うことで、ファイルを以前の状態まで戻したり、プロジェクト丸ごとを以前の状態に戻したり、過去の変更履歴を比較したり、問題が起こっているかもしれないものを誰が最後に修正したか、誰がいつ問題点を混入させたかを確認したりといった様々なことができるようになります。 また、VCSを使うと、やっていることがめちゃくちゃになってしまったり、ファイルを失ったりしても、普通は簡単に復活させることができるようになります。 それに、これらのことにかかるオーバーヘッドは僅かなものです。
</div></details>

参照:[git バージョン管理に関して](https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6)より


### リポジトリとは

ファイルなどの保存場所。

決してデータベースやコンテナではないですが似たようなものです。

![repo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/7d38d4fe-3b9d-0c39-4836-89e589ba2f79.png)

## バージョン管理システムの種類

おおまかに3種類のバージョン管理システムがある。

- ローカルバージョン管理システム
- 集中バージョン管理システム
- 分散バージョン管理システム

### ローカルバージョン管理システム

ローカルにのみリポジトリがある。

![ローカルバージョン管理システム](https://git-scm.com/book/en/v2/images/local.png)

<details><summary>参考にした文章</summary><div>

>どのディレクトリにいるのか忘れやすく、うっかり間違ったファイルに書き込んだり、上書きするつもりのないファイルを上書きしてしまったりします。
この問題を扱うため、はるか昔のプログラマは、ローカルのVCSを開発しました。それは、バージョン管理下のファイルに対する全ての変更を保持するシンプルなデータベースによるものでした。
</div></details>

参照:[git ローカルバージョン管理システム](https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6)より

### 集中バージョン管理システム

1個のサーバーを用意してあげてそこのリポジトリに保存。

![集中バージョン管理システム](https://git-scm.com/book/en/v2/images/centralized.png)

<details><summary>参考にした文章</summary><div>

>次に人々が遭遇した大きな問題は、他のシステムを使う開発者と共同作業をする必要があるということです。
バージョン管理されたファイルを全て持つ一つのサーバーと、その中心点からファイルをチェックアウトする多数のクライアントからなっています。 長年の間、これはバージョン管理の標準でした。
</div></details>

参照:[git 集中バージョン管理システム](https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6)より

### 分散バージョン管理システム

ローカルにもサーバーにもリポジトリがある。
もしサーバーが死んでも大丈夫()。

![分散バージョン管理システム](https://git-scm.com/book/en/v2/images/distributed.png)

<details><summary>参考にした文章</summary><div>

>ここで分散バージョン管理システム(DVCS)の出番になります。 DVCS(Git、Mercurial、Bazaar、Darcsのようなもの)では、クライアントはファイルの最新スナップショットをチェックアウト（訳者注：バージョン管理システムから、作業ディレクトリにファイルやディレクトリをコピーすること）するだけではありません。リポジトリ（訳者注：バージョン管理の対象になるファイル、ディレクトリ、更新履歴などの一群）全体をミラーリングするのです。 そのため、あるサーバーが故障して、DVCSがそのサーバーを介して連携していたとしても、どれでもいいのでクライアント・リポジトリの一つをサーバーにコピーすれば修復できます。 クローンは全て、実際は全データの完全バックアップなのです。
</div></details>

参照:[git 分散バージョン管理システム](https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6)より

#### スナップショットで、差分ではない

commitが分かれば納得できると思う。
分散バージョン管理システムは一回一回全保存。
その他だと編集したファイルだけ保存。

- 分散バージョン管理システム
![スナップショット](https://git-scm.com/book/en/v2/images/deltas.png)

- その他のバージョン管理システム
![a](https://git-scm.com/book/en/v2/images/snapshots.png)

<details><summary>参考にした文章</summary><div>

>Gitと他のVCS (Subversionとその類を含む)の主要な相違は、Gitのデータについての考え方です。 概念的には、他のシステムのほとんどは、情報をファイルを基本とした変更のリストとして格納します。 これらのシステム（CVS、Subversion、Perforce、Bazaar等々）は、図1-4に描かれているように、システムが保持しているファイルの集合と、時間を通じてそれぞれのファイルに加えられた変更の情報を考えます。
Gitは、この方法ではデータを考えたり、格納しません。 代わりに、Gitはデータをミニ・ファイルシステムのスナップショットの集合のように考えます。 Gitで全てのコミット（訳注：commitとは変更を記録・保存するGitの操作。詳細は後の章を参照）をするとき、もしくはプロジェクトの状態を保存するとき、Gitは基本的に、その時の全てのファイルの状態のスナップショットを撮り（訳者注：意訳）、そのスナップショットへの参照を格納するのです。 効率化のため、ファイルに変更が無い場合は、Gitはファイルを再格納せず、既に格納してある、以前の同一のファイルへのリンクを格納します。 Gitは、むしろデータを*一連のスナップショット*のように考えます。
</div></details>

参照:[git Gitの基本](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%E5%9F%BA%E6%9C%AC)より

<details><summary>容量についての疑問点</summary><div>

#### ファイルの容量の確認

duコマンドで確認できる。duコマンドはディスクの使用量がわかる。

```
$ du -sh .git/objects/
```

#### 全保存ってことは

ファイルの容量は増えていくばかり...
と思ったら、```git-pack-objects```なるものがあり、勝手に圧縮してくれるすぐれものです。

</div></details>

## Gitを使用する上で最低限必要な用語

- ローカルリポジトリ
- リモートリポジトリ
- Gitサーバ
- add
- commit(コミット)
- push(プッシュ)
- clone(クローン)
- pull(プル)

### リポジトリとは(復習)

![repo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/7d38d4fe-3b9d-0c39-4836-89e589ba2f79.png)

### ローカルリポジトリとリモートリポジトリ

- ローカルリポジトリは自分のPC内にあるリポジトリのこと
- リモートリポジトリはGitサーバにあるリポジトリのこと

![repo_git_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/f2a563b9-3907-3a38-52f5-df957f8ec144.png)

### Gitサーバ

Git用に設定されたサーバです。

もちろん自分でたてられたりしますが、
[GitHub](https://github.com/)や[GitLab](https://about.gitlab.com/)などの無料で使えるクラウドサーバ(厳密には開発プラットホーム)もあります。

### 全体像

全体像はこんな感じ

![repo_git_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/95dfa767-42a1-76a6-6fef-0292fb08a23a.png)

### addとは

作業ファイルはリポジトリをコピーして「作業コピー」を取得します。
その作業コピーにたして変更を加えてあげることで、変更内容のスナップショットをリポジトリにコミットします。
ファイルの状態には追跡されている(tracked)や追跡されてない(untracked)があり、
追跡されている(tracked)状態の「変更されている(modified)」ファイルを「ステージされている(staged)」状態にするために行うことが```add```です。

![staging](https://git-scm.com/book/en/v2/images/lifecycle.png)


### commit(コミット)してpush(プッシュ)

- commitはローカルリポジトリにファイルを保存すること。
- pushはリモートリポジトリにローカルリポジトリを保存すること。

gifだと分かりやすく新しいファイルのみpushしていますが、実際はリポジトリごとpushしています。

![gif_push_git.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/78ed789d-345a-bf2d-f327-6680bef9501e.gif)

#### ここで行っているadd,commit,pushコマンド

```
$ git add [file]
$ git commit -m "[comment]"
$ git push -u origin master
```

### cloneとpullの違い

ローカルリポジトリがあるかないかです。

つまり自分のPCにデータがあるかないかです。

- cloneはローカルリポジトリがないとき
- pullはローカルリポジトリがあるとき

### clone

リモートリポジトリにリポジトリがあるがローカルリポジトリにリポジトリがない時に行います。

つまり、サーバにだけデータベースがあって自分のPCにデータベースがない時に使用するコマンドです。

![gif_clone_git.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/7b4aa229-6288-f245-6ae8-cce11bad7217.gif)

#### ここで行っているcloneコマンド

```
$ git clone [URL]
```

### pull

他人がリモートリポジトリにもリポジトリが変更した時、自分もそのリポジトリをローカルリポジトリにダウンロードする必要があります。

つまり他人がサーバにデータを保存した時、それをダウンロードするために使用するコマンドです。

![gif_pull_git.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550501/4bbfabb4-9e90-c9b6-3f27-278546f4f875.gif)

#### ここで行っているpushコマンド

```
$ git pull origin master
```

## コマンドの流れ

### ローカルリポジトリをGitHubにpushする

#### 1回目

```
$ mkdir [file name]
$ cd [file name]
$ echo "hello,world" >> README.md
$ git init
$ git add [file name]
$ git commit -m "[comment]"
$ git remote add origin [URL]
$ git push -u origin master
```

#### 2回目以降

```
$ git add .
$ git commit -m "comment"
$ git push -u origin master
```

### リモートリポジトリからローカルリポジトリにcloneしてくる

```
$ git clone [URL]
```

### リモートリポジトリからローカルリポジトリにpullしてくる

```
$ git pull origin master
```

## まとめ

- バージョン管理には種類がある。
- リポジトリはファイルの保存場所
- アップロードはaddしてcommitしてpush
- ダウンロードはclone or pull

## 参照

[Git 公式ドキュメント-日本語](https://git-scm.com/book/ja/v2)