見出し画像

Gitとはなにか?歴史から機能、使い方まで読み解く。

どうも、久しぶりに記事を書いた、なかむです。
今回は6/13から始まったX-Hackさんの「JavaScriptを極める3ヶ月!アプリ開発の知識を徹底的に学ぶ」という勉強会の一環としてGitとは何かということを、初心者向けに書いてみようと思います。(あとは自分の知識の整理のため)

・Gitはどのようにつくられたのか?その歴史を簡単に紹介


Gitとは簡単に言うとバージョン管理ツールです。
Linuxの開発者の一人であるリーナス・トーバルズ等によって作られました。

画像1

↑NVIDIAのサポートにLinuxが対応されていないことにキレた
リーナス・トーバルズ

元々Linuxカーネルの制作をしているときに、他の開発者のやり取りに、Zipファイルを送ったりしたりしてソースコードを管理していました。
が、管理するのが面倒なのでBitKeeperというバージョン管理システムを使っていました。
しかし、BitKeeper社と色々揉めてしまいます。(詳しいことは割愛)
それで、リーナスたちは「じゃあ自分たちで作るか!」と作られたのがGitとなります。

・バージョン管理システムって?

さて、上記に出した、「バージョン管理システム」という
ワードがでました。
これは、「コンピュータ上で作成および編集されるファイルの変更履歴を管理するためのシステム」の事を指します。
どのような時に役立つでしょうか?導入されるべき身近な例を
2つ出しましょう。

例えば、あなたの会社では社内ネットワーク上でExcel等の帳簿ファイル作成しているとしましょう。色々な方が編集、更新しますが、そのバージョン管理する場合どのような方法で行うのでしょうか?
多くの場合は、名前で分けると思います。
が、この様な状態になりがちだと思います。「日付-名前-メモ...」

Excelイライラ

まだ、4つなら見分けがつくものも、50個、100個ファイルがネットワーク上に多くあったら、見分けがつかないと思いますし
過去のファイルから修正するときも「あれ、どれだっけ?」
みたいなことが多く出てくると思います。めんどくさいですね!

2つ目の例ですが、社内ネットワーク内にあるファイルを編集したい
(今回もExcelファイル)と思った時に、このような画面になると思います。

Excelいらいら2

これは、別の人がファイルを編集している途中だった時に出るのですが
自分の作業が中断されて、イライラすることがあると思います。
(事実僕もよくある)

あとは、ネットワークサーバーが停止した場合、その中にあるファイルの
作業ができなかったり。。。色々と不便なことがあると思います。

これらの例の対処法として、バージョン管理システムというものが
役立つのです。

※バージョン管理は集中型、分散型にとありますが、
 ここでは詳しい事は省きます。
 Gitは、分散型バージョン管理システムに当てはまります。
 なので、ここでは分散型バージョン管理システムの方を解説します。

・リポジトリという概念について

まず、サーバー上にリポジトリというものがあります。
これは、バージョン管理の対象になるファイル自体、ディレクトリ
更新履歴などのデータ
が入っています。それらのリポジトリを
各自のコンピューターにコピーしていきます。(Gitコマンドでいうclone)

分散型

出典画像:1.1 使い始める - バージョン管理に関して-git

git clone 'クローンしたいリポジトリのURL'

この様に、リポジトリを分散させることで、リポジトリ内のファイル編集を行う時に、サーバーではなく各コンピューターにあるリポジトリを使って編集すればいいので、同時進行にファイルを編集することができます。

また、サーバーが停止したとしても、各コンピュータにあるリポジトリに
影響受けずにファイルの編集ができます。
ちなみに、サーバー上にあるリポジトリをリモートリポジトリ。
各コンピューター内にあるリポジトリをローカルリポジトリと呼びます。

ちなみに、リモートリポジトリからクローンせずにローカル環境から
リポジトリを作成したい場合、リポジトリを作成したいディレクトリ上で
initコマンドを使用したらリポジトリが作られます。

$ pwd
/c/Users/Ryota Nakamura/test_git
//test_gitというディレクトリがある

$ git init
Initialized empty Git repository in C:/Users/Ryota Nakamura/test_git/.git/
//git initでリポジトリが作成される

$ ls -a
.  ..  .git  test.html
//ls -aでファイルを確認(-aで隠しファイルも表示される)

ここで隠しファイルである.gitがあるのが分かると思いますが
.gitはリポジトリを追跡するファイルとなります。

次に、ローカルリポジトリの更新はどのように行うのでしょうか?
例えばコンピューターAがファイル内のローカルリポジトリを更新するとします。データの中身自体は保存だけで済みますが、ローカルリポジトリ自体には何も影響を受けません。
ローカル(リモート)リポジトリはバージョン管理の対象になる
ファイル自体、ディレクトリ、更新履歴などのデータ
をまとめて管理しているのでファイルの更新だけではローカルリポジトリは更新されません。
ローカルリポジトリを更新したいと思ったときはGitでいうadd、commitというコマンドを使います。

まず、git addで変更したいファイルを指定します。

$ git add test.html 
//test.htmlファイルを変更したいファイルとして指定。

$ git status
//git statusでどれをaddされたか、確認。

On branch master
//ブランチマスター(ブランチはのちに解説)で

No commits yet
//コミットはまだされていません。

Changes to be committed:
(use "git rm --cached <file>..." to unstage)
      new file:   test.html
//更新される予定のファイルは「new file:   test.html」です。

これで、更新の準備ができました。

Commitコマンドでローカルリポジトリを更新してみましょう。
Commitはオプションコマンド-mを使用しコメントを残していきます。

$ git commit -m '最初のコミット'
[master (root-commit) ea01bd9] 最初のコミット
1 file changed, 11 insertions(+)
create mode 100644 test.html

これで、ローカルリポジトリの更新がされました。
コンピューターAのみのローカルリポジトリのみ更新したという
ことなので他のコンピューターのローカルリポジトリ、サーバーの
リモートリポジトリに影響を受けません。

ここまでで、ローカルリポジトリが更新されました。
つぎに、共用サーバー上にあるリモートリポジトリを更新しましょう

リモートリポジトリの時はGitではPushというコマンドを使います。

リモートリポジトリはGitHubを使用します。GitHubのメニューから
リモートリポジトリを作成しましょう。

まず、GitHubのメニューに入り、左の「New」からリポジトリを作成します。

無題

遷移した画面で、リポジトリの名前を付け、create repositoryを押します。
今回はリポジトリネームを「Test_Git」としました。

無題

これで、GitHubにリモートリポジトリができました。

無題

画面上で、リモートリポジトリに反映させるためのコマンドが表示されますので、更新したいローカルリポジトリ上にここのリモートリポジトリに
反映させましょう。

※ちなみに、GitHubに通信する時にHTTPSかSSHかどちらかのプロトコルを選択できます。今回のプロトコルはHTTPSをつかいます。
HTTPS、SSHはどちらもクライアントとサーバーとのやり取りに使われる
プロトコル(通信をする際の手順)ですが、違いなどを説明すると長くなるので割愛します。

まず、remote addでどのリモートリポジトリにアクセスするか指定します。

$git remote add origin https://github.com/ryo-n-cell/Test_Git.git
//originをhttps://github.com/ユーザー名/リポジトリ名.gitと結びつける

$ git config --get remote.origin.url
https://github.com/ryo-n-cell/Test_Git.git
//git config --getでリモートされているoriginのURLを確認

origin=リポジトリの場所(URL)の別名を指します。
後々のGitHubの作業で毎回URLを指定するのはめんどくさいので
このコマンドで、originを「https://github.com/ryo-n-cell/Test_Git.git」
に結び付けるよ!という命令を出しているのですね。

※そのほかの確認方法

ローカルリポジトリとリモートリポジトリを結びつけました。
次にリモートリポジトリを反映させましょう。
コマンドはPushを使います。

$  git push origin master
//originをmasterブランチ(のちに解説)に反映させる。
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 6 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 385 bytes | 385.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/ryo-n-cell/Test_Git.git
* [new branch]      master -> master

これで、GitHub上のリモートリポジトリに反映されました。
GitHubで確認しましょう。

無題

これでOKですね!

・ブランチの概念と仕組み

チーム開発をするとき欠かせないブランチの概念について説明します。
 

ブランチ(=枝)とは何でしょうか?
一言で表すと、リポジトリの履歴の流れを分岐して記録していくためのものです。下の図を見てみましょう。

branch-ページ1のコピーのコピー

まず、クライアント(=作業している人たち)A、B、Cがいるとします。
初めにあるリモートリポジトリの「リポジトリ1.0」をクライアントA、Bはclone(①)します。ローカルmasterブランチ自体はあるので
各自作業ブランチを作成します。(②)
作業する所は作業ブランチ上で行いローカルmasterブランチには
作業を行いません

で、先にAが作業した作業ブランチをリモートmasterブランチに反映させたいためPushしています。(③)
その後、チームリーダがAの作業ブランチをリモートmasterブランチに反映させてもいいのか確認してOKでしたらGitHub上でmergeを行います(④)
その後、Bの作業が完了したので自分の作業ブランチをリモートmasterブランチにPushして更新しています。(⑤)
こちらも、チームリーダーがBの作業ブランチをリモートmasterブランチに反映させてもいいのか確認して、GitHub上でmergeを行います(⑥)
のちに新しい箇所の開発を任されたAは、fetchとmergeを行い
自分の
ローカルmasterブランチにリモートmasterブランチをコピーして
作業を行います。(⑦)
Bも新しい箇所の開発を任されましたので、Pullを行い自分のローカルmasterブランチにマスターブランチをコピーして作業を行いました。(⑧)
※実はチーム開発においてPullを行うのは好ましくないらしいです。
 理由は以下の通り。リモートブランチにPullを使用すると
 ローカルのマスターブランチにmergeされて
 しまうとか。この部分が分かれば気にしなくてもよい気がしますが。。。
 まぁ、チームの方針優先次第で。

その後、クライアントCが途中参加してきたのでCがリモートリポジトリから自分のPCへcloneしました(⑨)

さて、いくつか新しいコマンドが出てきました。merge、fetch、Pullですね。簡単に説明すると
merge:= 併合する。ブランチ同士を併合して、
    併合されたブランチを更新する。

fetch:=取ってくる。リモートリポジトリから最新情報を
    ローカルリポジトリに持ってくるコマンド

※更新されたリモートリポジトリを自分のブランチにコピーする
 順番はfetch→merge
Pull:=引っ張る。上記のfetch→mergeをまとめて行う。
   mergeされる所はdevelopブランチにされるので注意。

という形になります。

また、チームによってブランチモデルは様々あります。
もし、プロジェクトに途中参加されるならば、どのようなブランチモデルに
なっているか、理解することが大切ですね。

・実際にブランチ作成→リモートリポジトリPush
 →fetch&mergeを行う

さて、作業の続きとしてTest_Gitリポジトリのブランチ作成から
行っていきましょう。

ブランチの作成はbranchコマンドを使用します

$ git branch "test1"
//git branch"ブランチ名"で作成

$ git branch
//git branchで今いるブランチの確認
* master
 test1

$ git checkout test1 
Switched to branch 'test1
//git checkout ブランチ名 でブランチの移動

$ git branch
 master
* test1
//test1ブランチの移動が確認された

$ git status 
//git自体の確認
On branch test1
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:   test.html
no changes added to commit (use "git add" and/or "git commit -a")

これで、test1のブランチが作られました。
このtest1ブランチ上で作業を行うわけですね。

次に作業したtest1ブランチを、Commitしてみましょう。

$ git add test.html 
//作業を行ったtest.htmlファイルを指定

$ git status
On branch test1
Changes to be committed:
 (use "git restore --staged <file>..." to unstage)
       modified:   test.html
//更新される予定のファイルは「new file:   test.html」です。

$ git commit -m "merge_test"
[test1 2eb1c05] merge_test
1 file changed, 1 insertion(+), 1 deletion(-)
//merge_testをコミット

$ git checkout master
Switched to branch 'master'
//ローカルmasterブランチに移動

$ git merge test1 
Updating ea01bd9..2eb1c05
Fast-forward
test.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
//test1 ブランチに
※ここまではGitHub上のリモートmasterブランチに反映されていない

これで、作業ブランチの内容が、Commitされました。
コミットメッセージは「merge_test」です。

次にGitHub上にあるリポジトリにコミットされた
test1ブランチをPushしてみます

$ git push origin test1 
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 6 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 299 bytes | 299.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: 
remote: Create a pull request for 'test1' on GitHub by visiting:
remote:      https://github.com/ryo-n-cell/Test_Git/pull/new/test1
remote:
To https://github.com/ryo-n-cell/Test_Git.git
* [new branch]      test1 -> test1

これで、GitHub上のリポジトリに test1 ブランチが反映されました。

無題

つぎにGitHub上でtest1ブランチとマスターブランチをmergeさせましょう。
上の画像のCompare & pull requestボタンを押します。

無題

下にスクロールしてファイルの変更箇所に問題がなければCreate pull requestボタンを押します。

無題

Merge pull requestボタンを押しましょう。
※この画面はリクエストを送った作業ブランチと、masterブランチを
mergeしてもよいのか確認する画面なので、チーム開発をしている場合は
開発リーダーによってmergeしてもよいのか判断されます。

これで、masterブランチにmergeされました。コミットメッセージにある「merge_test」が表示されてますね。

無題

では、反映されたリモートmasterブランチを
ローカルmasterブランチにmergeしましょう。
これは、fetchとmergeを使います。

$ git branch 
* master
  test1

$ git fetch origin master
From https://github.com/ryo-n-cell/Test_Git
* branch            master     -> FETCH_HEAD
//リモートリポジトリの最新の履歴の取得だけを行う

$ git merge origin/master
Updating 2eb1c05..8c9ce09
Fast-forward
//masterブランチに

これで、リモートmasterブランチをローカルmasterブランチに
反映させました。

・最後に

Gitを初めて扱う人はナニコレ?となることが多いです。
実際僕もそうでしたし。

ですが、Gitの概念が分かれば開発のバージョン管理が楽になります。
是非、Gitの使い方を覚えていきましょう!

あとがき:ブランチの説明文を書くときに、ブランチというワードが多すぎてゲシュタルト崩壊したので、ここが違うよというところがあれば教えていただけると嬉しいです。

6/15 記事を修正しました。HTPPS→HTTPS

この記事が気に入ったらサポートをしてみませんか?