Gitの導入方法と基本的な使い方(2)

カテゴリ:開発環境

Gitの導入方法と基本的な使い方(1)に引き続きGitについて解説していきたいと思います。
この記事ではGitのブランチ、クローン、リモートリポジトリ、プッシュ、プルについて解説いたします。

ブランチとは?

ブランチは「」を意味します。
アプリの開発はバージョンアップを繰り返しながら継続されていきますが、どこかのタイミングでアプリをリリースする必要があります。リリースした後も当然開発は継続されますが、顧客からバグの報告があったり、ユーザビリティの改善要望が出され修正を加える必要が出てくる場合があります。
そういったとき、すでに開発が進行中のバージョンに上記の修正を加えて最新バージョンとしてリリースしたいところですが、現在開発が進行中の機能の実装やテストがまだ完了しておらず、それらを待って修正を加えてリリースするのではリリースに時間がかかります。

そこで、現在進行中の開発(2.0予定)とは別に、リリースバージョン(1.0)に緊急の修正を加え、修正版バージョン(1.1)をリリースする必要が出てきます。

この場合、現在進行中の開発バージョンと並行して、リリースバージョンに修正を加えた予定外のバージョンの両方が存在してしまうことになり、これらは分けて開発したいところです。
ブランチはこういったメインの開発バージョンから分岐させて、少し手を加えたい場合に利用します。

ブランチを作る(git branch)

ブランチは「枝」と言いましたが、メインのブランチは「」となり、デフォルトでmasterというブランチに入っています。
現在のブランチを確認するためには、git branchコマンドを実行します。
git branch
例)
$ git branch
* master
masterと表示され、先頭に*が付いていますね。これが現在いるブランチを表しています。ブランチを作成していない場合は、このmasterブランチにいる状態です。

では新しいブランチを作ってみましょう。
ブランチを作成する場合は、git branchコマンドに続けてブランチ名を指定します。

git branch 作成するブランチ名
ブランチ名をapp01として作成してみます。
$ git branch app01
もう一度、git branchコマンドを実行してみましょう。
$ git branch
  app01
* master
master以外にapp01というブランチが表示されましたね。

ブランチを変更する(git checkout)

では、作成したapp01のブランチに移動してみましょう。
ブランチを変更するにはgit checkoutコマンドに続けて変更先のブランチ名を指定します。
git checkout 変更先のブランチ名
例)
$ git checkout app01
Switched to branch 'app01'
app01にブランチをスイッチした旨のメッセージが表示されましたね。
git branchコマンドを実行してみましょう。
$ git branch
* app01
  master
app01ブランチに移動している事が確認できます。
これで、masterから分岐したブランチapp01をリリースし、もしリリース後に緊急修正が必要となった場合は、app01ブランチのコードを修正し再リリースすれば良いことになります。
masterはそのapp01の修正とは関係なく新バージョンの機能実装を進め、後でapp01ブランチに加えた修正をマージして次期バージョンをリリースする流れになります。もちろん次期バージョンのリリース時にはブランチapp02を作成してリリースすることになります。

ブランチをマージする(git merge)

ブランチで変更したファイルを他のブランチにマージする場合はgit mergeコマンドを使用します。
git merge マージ元のブランチ名
app01ブランチのapp01.jsファイルを変更してadd、commitを実行後に、masterブランチにマージしてみましょう。

まず、masterブランチにチェックアウトします。

$ git checkout master
Switched to branch 'master'
そしてapp01ブランチのファイルをマージします。
$ git merge app01
Updating 179fb04..5af0e3c
Fast-forward
 app01.js | 1 +
 1 file changed, 1 insertion(+)
マージが成功すれば上記のようにSHA1が更新された旨と、変更されたファイル名(app01.js)が表示されます。
マージは正常に行われましたね。

では、app01ブランチを作成後に、masterブランチとapp01ブランチの両方のapp01.jsファイルに異なる変更が加えられていた場合はどうなるでしょう?
その場合、Gitは差分を自動解決できないためマージできず、以下の例のように競合(Conflict)が発生してしまいます。

例)

$ git merge app01
Auto-merging app01.js
CONFLICT (content): Merge conflict in app01.js
Automatic merge failed; fix conflicts and then commit the result.
この場合は、一旦git merge --abortコマンドでマージ前の状態に戻し、どのようにマージするかを開発者間で検討(人間が解決)する必要があります。

クローン(git clone)

クローンはリポジトリの複製を行います。
git cloneコマンドに続けて、複製するリポジトリ名と複製先のリポジトリ名を指定します。
git clone 複製元のリポジトリ名 複製先のリポジトリ名
複製するにはリポジトリのフォルダの1つ上の階層に移動してから、git cloneコマンドを実行します。
以下の例ではapp01リポジトリフォルダの1つ上の階層に移動し、app01のクローンであるapp01.cloneを作成しています。

Noteもしmaster以外のブランチに入っている場合、複製するときは、masterブランチにチェックアウトしておきます。

$ cd ..
$ git clone app01 app01.clone
Cloning into 'app01.clone'...
done.
lsコマンドで複製されたapp01.cloneフォルダが確認できるはずです。
$ ls
app01  app01.clone
複製したリポジトリは複製元のリポジトリ(デフォルトはorigin)を知っており、リモートリポジトリとして参照します。

参考通常、リモートリポジトリはネットワーク上にあり、クローン元にはそのURLを指定します。
なお、クラウド上でリモートリポジトリを提供しているサービスとしてGitHubが広く知られています。(制限付きですが、現在プライベートリポジトリも無料で使用可能)

リモートリポジトリ(git remote)

複数人や複数のチームで共同で開発する場合、ローカルリポジトリで開発したファイルをある段階で同期する必要があります。
他の開発者が作成・編集したファイルはリモートリポジトリと呼ばれる共有フォルダに保存されています。

リモートリポジトリはgit remoteコマンドで確認できます。
先ほど作成したクローンであるapp01.cloneフォルダに移動し、git remoteコマンドを実行してみます。

例)

$ cd app01.clone/
$ git remote
origin
上記のようにリモートリポジトリとしてoriginが表示されるはずです。originは複製元のリポジトリ(app01)を表しています。 つまりクローンapp01.cloneにとって、app01がリモートリポジトリになるのです。

また、git ls-remoteコマンドでリモートリポジトリが有するリファレンスのSHA1を確認できます。
以下の例ではoriginリモートリポジトリのリファレンスを表示しています。

$ git ls-remote origin
6c96b0e1a3291ea2ed076294e45ef03fc8d3c8b2        HEAD
6c96b0e1a3291ea2ed076294e45ef03fc8d3c8b2        refs/heads/app01
6c96b0e1a3291ea2ed076294e45ef03fc8d3c8b2        refs/heads/master

リモートリポジトリに保存する(git push)

ローカルリポジトリのファイルをリモートリポジトリに保存する行為をプッシュと呼びます。
Gitではgit pushというコマンドを用いてプッシュします。
git push リモートリポジトリ名 ブランチ名
以下の例では、originという名前のリモートリポジトリのmasterブランチにプッシュします。
まず、クローンのmasterブランチにチェックアウトした上で、git push origin masterを実行します。

例)

$ git checkout master
Branch 'master' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'master'
$ git push origin master
Everything up-to-date
Everything up-to-date」と表示されていますが、これは何も変更していない、つまりプッシュするファイルが無かった場合の表示です。
クローンのファイルを変更して、add、commitしてから、再度プッシュしてみましょう。
$ git add app01.js
$ git commit -m "3rd Commit"
[master 7a6fa8e] 3rd Commit
 1 file changed, 1 insertion(+)
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 358 bytes | 51.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /mnt/c/Users/foo/Documents/VSC/javascript/app01
   6c96b0e..7a6fa8e  master -> master
はい、リモートリポジトリ(app01)のmasterブランチにオブジェクトを保存(Writing objects)した旨が出力されましたね。
6c96b0e..7a6fa8e master -> master」はリモートリポジトリのmasterのSHA1が6c96b0eから7a6fa8eに変更された事を示しています。
これでリモートリポジトリに先ほど変更されたファイルが保存(更新)されているはずです。
git ls-remoteコマンドで確認してみます。
$ git ls-remote origin
6c96b0e1a3291ea2ed076294e45ef03fc8d3c8b2        HEAD
6c96b0e1a3291ea2ed076294e45ef03fc8d3c8b2        refs/heads/app01
7a6fa8e1c6aada10745343c4a7b8fc5d52fc96ff        refs/heads/master
確かに変更されていますね。
ちなみにgit remote -v showコマンドを実行することで、リモートリポジトリの詳細が確認できます。
originリモーリポジトリの詳細を確認する場合は、最後にoriginを指定します。
$ git remote -v show origin
* remote origin
  Fetch URL: /mnt/c/Users/foo/Documents/VSC/javascript/app01
  Push  URL: /mnt/c/Users/foo/Documents/VSC/javascript/app01
  HEAD branch: app01
  Remote branches:
    app01  tracked
    master tracked
  Local branches configured for 'git pull':
    app01  merges with remote app01
    master merges with remote master
  Local refs configured for 'git push':
    app01  pushes to app01  (up to date)
    master pushes to master (up to date)

リモートリポジトリから取得する(git pull)

リモートリポジトリにあるファイルを取得してローカルリポジトリに同期する場合はgit pullコマンドに続けて取得元のリモートリポジトリ名とブランチ名を指定します。
git pull リモートリポジトリ名 ブランチ名
なお、git pullはgit mergeも同時に実行するため、差分は自動で解決されます。
以下の例ではoriginという名前のリモートリポジトリのmasterブランチから取得(同期)しています。

例)

$ git pull origin master
From /mnt/c/Users/foo/Documents/VSC/javascript/app01
 * branch            master     -> FETCH_HEAD
Already up to date.
Already up to date.」と表示されていますがこれは何も更新が無かった事を示します。
リモートリポジトリ側のmasterブランチのファイルが更新(SHA1が変更)されていた場合はどうなるでしょうか。
通常、これは同じリモートリポジトリのmasterブランチに他の人(ローカルリポジトリ)がプッシュした場合に発生します。

試しに、リモートリポジトリ(app01)のmasterブランチでファイルを変更し、addとcommitを実行してみましょう。

例)

$ git commit -a -m "4th Commit"
[master a146557] 4th Commit
 1 file changed, 1 insertion(+), 1 deletion(-)
そして、クローン(app01.clone)のmasterブランチに入り、git pull origin masterを実行してみます。
$ git pull origin master
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /mnt/c/Users/foo/Documents/VSC/javascript/app01
 * branch            master     -> FETCH_HEAD
   7a6fa8e..a146557  master     -> origin/master
Updating 7a6fa8e..a146557
Fast-forward
 app01.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
リモートリポジトリ側のmasterブランチのSHA1が7a6fa8eからa146557に更新されており、ファイルapp01.jsが変更されている事を検出した旨が表示されていますね。
git logコマンドで確認すると、a146557は「4th Commit」というコミットメッセージでbarによって更新されていることが分かります。
$ git log
commit a1465571123d705e28392872e8a5daa71dffa448 (HEAD -> master, origin/master)
Author: bar 
Date:   Sun Nov 24 23:08:05 2019 +0900

    4th Commit

commit 7a6fa8e1c6aada10745343c4a7b8fc5d52fc96ff
Author: foo 
Date:   Sun Nov 24 22:37:34 2019 +0900

    3rd Commit
git diffコマンドで自分が最後にコミットした「3rd Commit」との差分を確認してみます。
$ git diff 7a6fa8e
diff --git a/app01.js b/app01.js
index ee630a2..f4b409d 100644
--- a/app01.js
+++ b/app01.js
@@ -1,4 +1,4 @@
 function getDaysOfMonth(year, month) {
-    //指定された年月の日数を返す
+    //指定された年/月の日数を返す
     return new Date(year, month, 0).getDate();
 }
コメント文にちょっと変更が加えられていただけでしたね。(あくまでもサンプルですので)

注意但しgit pullの場合は競合(Conflict)が起きる場合もありますので、その場合は個別の対処が必要となります。

以上、Gitのブランチとマージ、クローン、リモートリポジトリ、プッシュ、プルについて解説いたしました。

オススメ書籍:
こちらの「独習Git」は解説が分かりやすく(翻訳が秀逸)、且つ丁寧に解説されていて非常にお勧めですよ。Gitに関してはこの1冊で十分です。

公開日時: 2019年11月24日  23:41:47

本格的なスキルを身につける

オンラインによるWebプログラミングスクールの無料レッスンを受けてみたい方はTechAcademyの無料体験がおすすめですよ。

開発環境に戻る

このページのトップに戻る