2022 年度 OSS リテラシー 3 : Git, GitHub 入門 (1)
インストール
まず始めに, git がインストールされているか確認する. dpkg -l コマンドでインストールされているパッケージを一覧することができる. インストールされている場合は, 以下のように表示される. 先頭に ii がついているが, これはインストールされていることを意味する.
$ dpkg -l | grep git ... (略) ... ii git 1:2.30.2-1 amd64 fast, scalable, distributed revision control system ... (略) ...
インストールされていない場合は, apt-get でインストールする.
$ sudo apt-get update ... (略) ... $ sudo apt-get install git ... (略) ...
また, 以下のようにコマンドを打つと git のバージョンが確認できる.
$ git --version git version 2.30.2
git の初期設定を行う
$ git config --global user.name "名前" (自分の名前をローマ字で書くこと) $ git config --global user.email "メールアドレス" (自分のメールアドレス)
これにより, ~/.gitconfig に設定が記録される.
$ cat ~/.gitconfig [user] name = sugiyama email = sugiyama@matsue-ct.jp
git の基本的な使い方 (ローカルリポジトリ)
git init
まず, リポジトリの初期化を行う. ディレクトリを作成した上で, git init を実行する.
$ cd (ホームディレクトリに移動) $ mkdir git-tutorial $ cd git-tutorial $ git init Initialized empty Git repository in /home/sugiyama/git-tutorial/.git/
git status
作成したリポジトリの状態を確認するには git status を実行する. 現在は "master" ブランチにいることが表示される. また, 最終行に "nothing to commit" と書かれているように, コミット (commit) すべきファイルが存在しないことも示されている.
$ git status On branch master <-- 現在は master ブランチであることを示す Initial commit nothing to commit (create/copy files and use "git add" to track)
コミットが無いということは, 現時点では作成したリポジトリ (git-tutorial) には 何のファイルの何の状態も記録されていないということを意味する. 最初のコミットをするために管理の対象になる README.md ファイルを作成する. 管理対象となるファイルをワークツリー (git-tutorial ディレクトリ) 内に作成すれば良い.
$ touch README.md (中身は空なファイルを作る) $ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) README.md nothing added to commit but untracked files present (use "git add" to track)
"Untracked files" に作成した README.md ファイルが表示されていることが確認できる. このように Git のワークツリーやリポジトリに対して何らかの操作を行うと git status コマンドでの表示が変化する.
git add
Git リポジトリのワーキングツリーでファイルを作成しただけでは, Git リポジトリのバージョン管理の対象としてファイルは登録されていない. そのため, README.md ファイルは git status コマンドの表示で "Untracked files" に表示されていた.
そこでファイルを Git リポジトリの管理対象とするために git add コマンドを実行して, ステージ領域と呼ばれる場所にファイルを登録する. ステージ領域とはコミットをする前の一時領域である.
$ git add README.md $ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: README.md
README.md ファイルをステージ領域に登録したことにより, git status コマンドの 表示が変化した. "Changes to be committed" に README.md ファイルが表示されていることが確認できる.
git commit
git commit コマンドは, ステージ領域に登録されている時点のファイル群を 実際にリポジトリの歴史として記録するコマンドである. この記録を元にファイルをワーキングツリーに復元することが可能となる.
早速, git commit を実行する. "-m" オプションの値 "first commit" は コミットメッセージと呼ばれるもので, 後述する git log で参照できる. コミットメッセージにはコミットに関する要約を書くべきものである.
$ git commit -m "first commit" [master (root-commit) 1bab8be] first commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md
詳細なコミットメッセージを残す場合は -m オプションを付けずに git commit を実行する. まず, コミットした時に立ち上がるエディターを vi に指定する.
$ export EDITOR=vi
先に commit したので, 実行すると "nothing to commit" と言われる. そのため, README.md ファイルを修正する.
$ git commit On branch master nothing to commit, working tree clean $ vi README.md Git tutorial (ファイル名に何らかの文字列を書き込む)
改めてコミットする. そのまま git commit するとステージ領域に書き出していないと 文句を言われる. git add してから git commit する.
$ git commit On branch master Changes not staged for commit: modified: README.md no changes added to commit (変更が add されていないことを示す) $ git add README.md $ git commit [master cb505d7] 2017-11-20 README.md is modified by sugiyama 1 file changed, 1 insertion(+)
git commit を実行すると, エディター (vi) が起動する. コミットメッセージを記述する. コミットメッセージの書式は開発者同士で取り決めておくと良い. 以下の例では変更内容の要約を 1 行で記述している. また, コミットメッセージを何も書かないと commit されないので注意すること.
# Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # modified: README.md # 2018-11-03 modified by sugiyama
コミット後の状態を確認するには再度 git status を実行する.
$ git status On branch master nothing to commit, working tree clean
git log
git log コマンドはリポジトリにコミットされたログを確認できるコマンドである. 誰がいつコミットやマージをして, どのような差分が発生したかなどを確認できる. 先ほどの git commit コマンドが実際に記録されていることを確認してみる.
$ git log commit 2595cb1a2054d1ba71f2b08298c8e358031dd3fe (HEAD -> master) Author: SUGIYAMA Ko-ichiro <sugiyama@XXXX.jp> Date: Mon Oct 25 12:32:35 2021 +0900 2021-10-25 SUGIYAMA commit 6945552b6668022fc923b49d2da2e45c4552fcff Author: SUGIYAMA Ko-ichiro <sugiyama@XXXX.jp> Date: Mon Oct 25 12:31:35 2021 +0900 first commit
コミット欄の隣に書かれている "2595cb1a2054d1ba71f2b08298c8e358031dd3fe" が, このコミットを指し示すハッシュである. Author 欄には Git で設定されているユーザ名とメールアドレスが記録される.
git に登録されたファイルが複数になった場合, 特定のファイルのログだけ 確認したくなることがある. その場合はファイル名を指定する.
$ git log README.md ... (略) ...
コミットで行われた差分も確認する場合には -p をつけると, コミットメッセージの後ろにファイルの差分が表示される.
$ git log -p commit 2595cb1a2054d1ba71f2b08298c8e358031dd3fe (HEAD -> master) Author: SUGIYAMA Ko-ichiro <sugiyama@gfd-dennou.org> Date: Mon Oct 25 12:32:35 2021 +0900 2021-10-25 SUGIYAMA diff --git a/README.md b/README.md index e69de29..b399233 100644 --- a/README.md +++ b/README.md @@ -0,0 +1 @@ +Git tutorial <-- 先頭に + がついているのが追加した行 ... (略) ...
git diff
git diff は, ワークツリー・ステージ領域・最新コミット間の差分を 確認するために利用するコマンドである.
改めて README.md に書き込みをした後に git diff を実行することで 現在のワークツリーとステージ領域の差分を確認できる.
$ vi README.md It's Git tutorial (末尾に追加) $ git diff diff --git a/README.md b/README.md index b399233..7a4de2a 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ Git tutorial +It's Git tutorial <-- 先頭に + がついているのが追加した行
ステージ領域に変更を add する. この状態で git diff コマンドを実行すると ワークツリーとステージ領域の状態と差分が無いために何も表示されない. 最新コミットとの差分を確認するためには HEAD をつけて git diff を 実行する.
$ git add README.md $ git diff $ git diff HEAD diff --git a/README.md b/README.md index b399233..7a4de2a 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ Git tutorial +It's Git tutorial
git commit を実行する前に git diff HEAD を実行して, 今回のコミットが 前回のコミットからどのような差分があるのか確認をする癖をつけると良いだろう. 確認後に git commit する.
$ git commit -m "Add index" [master 383b15a] Add index 1 file changed, 1 insertion(+)
コミットの確認のために git log を実行する.
$ git log ... (略) ...
過去のコミットとの比較する場合は log の commit 欄のハッシュを用いる. 以下の例では log を確認し, 初期状態との比較を行う. "+" が付いている行が変更された部分である.
$ git log ... (中略) ... commit 6945552b6668022fc923b49d2da2e45c4552fcff <-- ここのハッシュを使う (各自の環境に合わせること) Author: SUGIYAMA Ko-ichiro <sugiyama@gfd-dennou.org> Date: Mon Oct 25 12:31:35 2021 +0900 first commit $ git diff 6945552b6668022fc923b49d2da2e45c4552fcff diff --git a/README.md b/README.md index e69de29..7a4de2a 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,2 @@ +Git tutorial +It's Git tutorial
git rm
ファイルの削除の練習をしてみる. 一度ファイルを作成し, それを削除する. ファイルを追加する場合に add => commit の順で行ったのと同様に, ファイルを削除する場合は rm => commit する. git rm した段階で ワーキングツリー内から該当ファイルは削除されるが, commit しないと最終的に反映されない.
まず始めに, テストファイルを用意する.
$ touch test.txt (ファイル作成) $ ls README.md test.txt $ git status (status の確認) On branch master Untracked files: (use "git add <file>..." to include in what will be committed) test.txt nothing added to commit but untracked files present (use "git add" to track) $ git add test.txt (ステージ領域にファイルを追加) $ git commit -m "add test.txt" (コミット) [master 1a061f5] add test.txt 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test.txt
次にテストファイルを削除する.
$ git rm test.txt rm 'test.txt' $ ls (ファイルが消えることが確認できる) README.md $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: test.txt $ git commit -m "remove test.txt" (git リポジトリに反映) [master 322bfbf] remove test.txt 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.txt
ブランチの操作
ブランチを活用することで複数の開発者が効率的に同時並行で開発を行うことができる. 開発者は Git のデフォルトのブランチである master ブランチから新たにブランチを作成し, その新規作成したブランチで開発作業を行う. 開発者が複数いる場合はブランチも複数存在することになる. 開発者は開発作業を一区切りさせたら, それぞれのブランチを master ブランチにマージする.
git branch
git branch は, ブランチ名の一覧を表示するとともに, 現在のブランチを 確認するためのコマンドである.
$ git branch * master
出力の中で, "*" (アスタリスク) の付いているのが現在のブランチである. 上記出力は, 現在は master ブランチにいること, ブランチは master のみ であることを意味する.
git checkout -b
現在の master ブランチから新しいブランチを作成するには, git checkout -b コマンドを用いる.
feature-A ブランチを作るには, 以下のようにコマンドを実行する.
$ git checkout -b feature-A Switched to a new branch 'feature-A'
このコマンドは, ブランチを作成し, 現在のブランチを feature-A に 移動するという 2 つの操作を同時に行うものである. 再び git branch コマンドを 実行すると, 現在は feature-A ブランチにいることがわかる.
$ git branch * feature-A master
それでは先に作成した README.md に 1 行追加してみる.
$ vi README.md test (feature-A) [最終行に追加]
この変更をコミットする.
$ git status On branch feature-A (<-- ここにブランチが feature-A であることが書かれている) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.md $ git add README.md $ git commit -m "Add feature-A" [feature-A 8d8cf00] Add feature-A 1 files changed, 1 insertion(+)
現在の状況を絵に表すと以下のようになる. 赤が master ブランチ, オレンジが 今作成した feature-A ブランチである. README.md を編集してコミットしたので, feature-A ブランチが master ブランチから分岐した.
次に, feature-A ブランチの変更が master ブランチに「影響しない」ことを 確認する. ブランチの切り替えは git checkout コマンドを用いる. 切り替えるだけなら -b オプションは必要ない.
$ git checkout master
先ほど feature-A ブランチで変更を加えた README.md を表示してみる. cat コマンドで確認すると, 先ほど加えた test (feature-A) が存在しないことがわかる.
$ cat README.md Git tutorial It's Git tutorial <-- 先ほど加えた "test (feature-A)" がない.
1 つ前のブランチ (feature-A) に戻す. 1 つ前のブランチに戻すには引数に "-" をつければよい. 表示されるメッセージから feature-A に切り替わったことがわかる. もちろん, "-" の代わりに feature-A と書いても良い.
$ git checkout - Switched to branch 'feature-A' $ cat README.md Git tutorial Git tutorial desu test (feature-A)
git merge
feature-A で行った作業 (例えば, バグ修正) が終わったあとは, feature-A の変更を master ブランチに統合する. まずは統合先のブランチ (master) へ移動する.
$ git checkout master Switched to branch 'master' $ git status On branch master (<-- master ブランチであることがわかる) nothing to commit, working tree clean
git merge コマンドを実行する. git merge コマンドを実行するとエディターが 起動する. エディターに vi を使いたい場合は予め環境変数 EDIOR を vi にしておくこと.
$ export EDITOR=vi $ git merge --no-ff feature-A Merge made by the 'recursive' strategy. README.md | 1 + 1 files changed, 1 insertion(+)
README.md ファイルの中を確認すると, feature-A ブランチに加えた変更が master ブランチに反映されていることがわかる.
$ cat README.md Git tutorial It's Git tutorial test (feature-A) <-- この行が増えた.
現在の状況を図に表すと以下のようになる. feature-A ブランチで行った変更が master ブランチに取り込まれた.
git log --graph
git log --graph コマンドを用いると, feature-A ブランチが分岐し 統合されたことをグラフィカルに表示することができる.
$ git log --graph * commit dc415cb8fa8bcb58cef82270cf885364f127ce9f |\ Merge: fe38f9a 8d8cf00 | | Author: sugiyama <sugiyama@matsue-ct.jp> | | Date: Sat Nov 25 06:03:35 2017 +0900 | | | | Merge branch 'feature-A' | | | * commit 8d8cf007d422a92f4616648c3583fd8c01f0176f |/ Author: sugiyama <sugiyama@matsue-ct.jp> | Date: Sat Nov 25 05:44:56 2017 +0900 | | Add feature-A | * commit 322bfbf4f15e9e75fe1a8f6c6ebdb3d9590c79c0 | Author: sugiyama <sugiyama@matsue-ct.jp> | Date: Tue Nov 21 02:37:07 2017 +0900 | | remove test.txt | .....(以下略).....
参考:コミットを変更する操作
git reset
バージョン管理のありがたいところは, 過去の情報に簡単に戻れることである. ここでは feature-A ブランチを分岐する前に戻って fix-B というブランチを作成する.
リポジトリの HEAD, ステージ, 現在のワーキングツリーを指定した状態まで 戻すには, git reset --hard コマンドを用いる. 引数に戻りたい場所のハッシュを 与えることで, そのときの状態を完全に復元することができる.
まずは戻す場所のハッシュを確認する. ブランチ分岐の前の commit の 横の文字列がハッシュである.
$ git log --graph ...(中略).... | | | * commit 935fb5ea065a779ae954d8942ad3962a47790296 (feature-A) |/ Author: SUGIYAMA Ko-ichiro <sugiyama@gfd-dennou.org> | Date: Mon Oct 25 12:58:32 2021 +0900 | | Add feature-A | * commit db754a4ef09a6008b94253d2d37e7d29f8d371bf <-- 分岐前のコミットのハッシュをコピー | Author: SUGIYAMA Ko-ichiro <sugiyama@gfd-dennou.org> | Date: Mon Oct 25 12:48:24 2021 +0900 | | remove test.txt ...(以下, 略)....
上記で得たハッシュを用いて git reset する.
$ git reset --hard db754a4ef09a6008b94253d2d37e7d29f8d371bf HEAD is now at db754a4 remove test.txt
リセットした後に README.md を確認すると, 最終行が消えていることがわかる.
$ cat README.md Git tutorial It's Git tutorial <-- 先ほど加えた "test (feature-A)" がない.
ここで fix-B ブランチを作成する. README.md ファイルを編集したあと, add と commit を行う.
$ git checkout -b fix-B Switched to a new branch 'fix-B' $ vi README.md test (fix-B) [末尾に追加] $ git add README.md $ git commit -m "ADD fix-B" [fix-B 1ba6722] ADD fix-B 1 file changed, 1 insertion(+)
また, git log コマンドを実行すると, master ブランチからの続きとして "fix-B" の変更が存在することがわかる.
$ git log --graph * commit ed30636b35054a87ef8d3febd1078ea8e5eef2c1 (HEAD -> fix-B) | Author: SUGIYAMA Ko-ichiro <sugiyama@gfd-dennou.org> | Date: Mon Oct 25 13:59:42 2021 +0900 | | ADD fix-B | * commit db754a4ef09a6008b94253d2d37e7d29f8d371bf (master) | Author: SUGIYAMA Ko-ichiro <sugiyama@gfd-dennou.org> | Date: Mon Oct 25 12:48:24 2021 +0900 | | remove test.txt | ... (略)...
現在の状況を図に表すと以下のようになる. feature-A を作ったところまで 戻ってから fix-B を作ったので, feature-A と fix-B の分岐点は同じである.
git reflog を実行すると, このレポジトリで行われた操作が全て確認できる. git reflog の出力を見ると, feature-A ブランチの作成とマージ, fix-B ブランチの 作成などを確認することができる.
$ git reflog ed30636 (HEAD -> fix-B) HEAD@{0}: commit: ADD fix-B db754a4 (master) HEAD@{1}: checkout: moving from master to fix-B db754a4 (master) HEAD@{2}: reset: moving to db754a4ef09a6008b94253d2d37e7d29f8d371bf fa4199f HEAD@{3}: merge feature-A: Merge made by the 'recursive' strategy. <-- ここが feature-A を master にマージしたところ db754a4 (master) HEAD@{4}: checkout: moving from feature-A to master 935fb5e (feature-A) HEAD@{5}: checkout: moving from master to feature-A db754a4 (master) HEAD@{6}: checkout: moving from feature-A to master 935fb5e (feature-A) HEAD@{7}: commit: Add feature-A db754a4 (master) HEAD@{8}: checkout: moving from master to feature-A db754a4 (master) HEAD@{9}: commit: remove test.txt 29dd09a HEAD@{10}: commit: add test.txt 383b15a HEAD@{11}: commit: Add index 2595cb1 HEAD@{12}: commit: 2021-10-25 SUGIYAMA 6945552 HEAD@{13}: commit (initial): first commit
feature-A ブランチをマージした後の状態は 4 行目の "merge feature-A: ..." であるので, そこに戻すには上記の例ではハッシュ fa4199f を使えば良い (ハッシュ値は各自の環境に合わせること). git log で 出力されるハッシュでも, git reflog で出力されるハッシュでも, どちらも使うことができる.
$ git status On branch fix-B nothing to commit, working tree clean $ git checkout master Switched to branch 'master' $ git reset --hard fa4199f HEAD is now at fa4199f Merge branch 'feature-A'
現時点の master ブランチは feature-A のマージを行った直後の状態になっているので, README.md は以下のようになっている.
$ cat README.md Git tutorial It's Git tutorial test (feature-A)
一方で, 先に作成した fix-B ブランチの README.md は以下のようになっている.
$ git checkout fix-B Switched to branch 'fix-B' $ cat README.md Git tutorial It's Git tutorial test (fix-B)
fix-B ブランチの README.md は過去の master ブランチの README.md を 元にしているので, master ブランチの最新の README.md の内容と食い違いが生じている. fix-B を feature-A にマージすると何がおこるだろうか?
$ git checkout master $ git merge --no-ff fix-B Auto-merging README.md CONFLICT (content): Merge conflict in README.md ^^^^^^^^^ Automatic merge failed; fix conflicts and then commit the result. ^^^^^^^^^^^^^^^^^^^^^^^
README.md ファイルに食い違いがあるので, コンフリクトが生じ, マージが失敗する. コンフリクト (CONFICT) は競合や衝突という意味である. git status を実行すると マージに失敗していることが表示される. メッセージには, コンフリクトを手動で修正して git commit を行うか, マージを中断する場合は git merge --abort を行うことが書かれている.
$ git status On branch master You have unmerged paths. (fix conflicts and run "git commit") <--- ここ! (use "git merge --abort" to abort the merge) <--- ここ! Unmerged paths: (use "git add <file>..." to mark resolution) both modified: README.md no changes added to commit (use "git add" and/or "git commit -a")
今回はコンフリクトを手動で修正してコミットすることにする. コンフリクトの生じたファイルを開くと以下のように衝突した部分が 表示される.
$ cat README.md Git tutorial It's Git tutorial <<<<<<< HEAD test (feature-A) ======= test (fix-B) >>>>>>> fix-B
今回は衝突した部分を両方共に生かすことにする. vi でファイルを開いて 以下のように修正する.
$ vi README.md Git tutorial It's Git tutorial test (feature-A) test (fix-B)
修正した結果をコミットする.
$ git add README.md $ git commit -m "fix conflict" [master 2bd4cd4] fix conflict
コンフリクトが解消されているので, 問題なくコミットされる.
現在の状況を図に表すと以下のようになる. feature-A を master にマージした ところまで戻ってから fix-B をマージした. この図からもわかるように, fix-B は feature-A の修正を取り込んだ後の master の状態は知らないので, fix-B を master にマージするときにコンフリクトが生じた.
GitHub のアカウント作成
<URL:https://github.com/> から GitHub のアカウントを作る. GitHub のアカウントは一生使うことを意識して, 恥ずかしくないアカウント名にすること.
Step2 で示されるプランでは, "Unlimited public repositories for free" を選択すること. 申請するとメールで確認がやってくる.
Personal access tokens の作成
以前は後述する GitHub へ git commit するときにパスワード認証が使えたが, つい最近にパスワード認証が禁止されてしまった.そのため, Personal access tokens を作成し,それを使う必要が生じた.
メニューの Settings から,Developer settings へ進み,Personal access tokens を選択する. そして,Create New Token をクリックする.
Note に適当なメモを残し,repo にチェックを入れておく
最終的に token が表示される.
もし token を忘れてしまった場合は,Web からログインし (2 段階認証), Personal access tokens のページに行く.「Regenerate token」が あるのでそれをクリックすると,token が再発行される.
リモートリポジトリ (GitHub) との連携
以下では GitHub 上のリモートリポジトリとの連携方法の基礎を行う.
まずは GitHub に同名のレポジトリ (git-tutorial) を用意する. 今回はライセンスや README の作成にはチェックを入れなくて良い.
git remote
リモートリポジトリを登録する. リポジトリのパスは Web 画面に表示されたように https://github.com/<ユーザ名>/git-tutorial.git である. これをローカルリポジトリの リーモートリポジトリとして登録するために git remote add コマンドを利用する. 以下のコマンド中のユーザ名は適宜自分のものに変更すること.
$ git remote add origin https://github.com/<ユーザ名>/git-tutorial.git
以降は origin という名前 (識別子) で GitHub のリポジトリを指すことができるようになる.
git push
現在のブランチのローカルリポジトリの内容をリモートリポジトリに 送信するためには, git push コマンドを用いる.
まずは現在のブランチを確認する. master ブランチであることがわかる. 最近,GitHub ではメインブランチ名が main となったので, branch -M で名前を変えてから git push すると良いだろう.
$ git branch feature-A fix-B * master $ git branch -M main $ git push -u origin main Username for 'https://github.com': <ユーザ名> <-- GitHub のユーザ名を入れる Password for 'https://sugiymki@github.com': <-- GitHub の token を入れる Counting objects: 27, done. Delta compression using up to 4 threads. Compressing objects: 100% (16/16), done. Writing objects: 100% (27/27), 2.23 KiB | 0 bytes/s, done. Total 27 (delta 4), reused 0 (delta 0) remote: Resolving deltas: 100% (4/4), done. To https://github.com/sugiymki/git-tutorial.git * [new branch] master -> master Branch master set up to track remote branch master from origin.
git push に -u origin main というオプションを与えたので, orgin という名前のリモートリポジトリ (今回は GitHub の git-tutorial リポジトリ) の main ブランチに ローカルリポジトリの main ブランチの内容が送信される.
当然のことながら, リモートリポジトリに main 以外のブランチを 作成することができる. 以下の例ではローカルリポジトリで feature-D というブランチを作成し, それをリモートリポジトリに送信する.
$ git checkout -b feature-D Switched to a new branch 'feature-D' $ git push -u origin feature-D Username for 'https://github.com': <ユーザ名> <-- GitHub のユーザ名を入れる Password for 'https://sugiymki@github.com': <-- GitHub の token を入れる Total 0 (delta 0), reused 0 (delta 0) To https://github.com/sugiymki/git-tutorial.git * [new branch] feature-D -> feature-D Branch feature-D set up to track remote branch feature-D from origin.
GitHub をブラウザで見ると, 新たに feature-D というブランチが存在することが確認できる.
現在の状況を図に表すと以下のようになる. feature-D が master から分岐した.
リモートリポジトリから取得
今までの作業で, GitHub に作成したリポジトリをリモートリポジトリとして 登録し, feature-D ブランチを push した. 次に, 「別の開発者」として リポジトリを取得してソースの修正やマージを行ってみる (下図の「開発者 B」の立場で).
git clone
まず, テスト用のディレクトリを自分のホームディレクトリ直下に作成する.
$ cd $ mkdir ~/test-remote $ cd test-remote
初めて GitHub 上のリモートリポジトリを取得する時には, git pull でなく git clone コマンドを用いる. GitHub 上のリポジトリは公開されているので, ユーザ名やパスワードを入力する必要はない.
$ git clone https://github.com/<ユーザ名>/git-tutorial.git Cloning into 'git-tutorial'... remote: Counting objects: 27, done. remote: Compressing objects: 100% (12/12), done. remote: Total 27 (delta 4), reused 27 (delta 4), pack-reused 0 Unpacking objects: 100% (27/27), done. $ ls git-tutorial $ cd git-tutorial
git status や git branch を実行すると, git clone を行った直後には master ブランチにいることがわかる. また, git status のメッセージ中に 'origin/master' とあるように, clone 元のリモートリポジトリは origin という名前で参照できるように自動的に設定されている.
$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean $ git branch * master
git branch に -a オプションをつけて実行すると, リモートリポジトリの 中に存在するブランチも表示することができる. リモートリポジトリ内に feature-D ブランチが存在することがわかる.
$ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/feature-D remotes/origin/master
リモートリポジトリの feature-D リポジトリをローカルリポジトリに チェックアウトするためには以下のようなオプションをつけて git checkout を実行する.
$ git checkout -b feature-D origin/feature-D Branch feature-D set up to track remote branch feature-D from origin. Switched to a new branch 'feature-D'
origin はリモートリポジトリを意味するので, origin/feature-D とすることで リモートリポジトリの feature-D リポジトリをチェックアウトすることができる. -b の直後の feature-D はローカルリポジトリ内でのブランチの名前である. 通常はリモートリポジトリのブランチ名と揃えると良い (ここでは feature-D).
feature-D ブランチのファイルを編集し, git add と git commit を行う.
$ git branch * feature-D master $ vi README.md Git tutorial It's Git tutorial test (feature-A) test (fix-B) test (feature-D) <-- 追記 $ git add README.md $ git commit -m "ADD feature-D" [feature-D 885d038] ADD feature-D 1 file changed, 5 insertions(+)
変更をリモートリポジトリに反映させる.
$ git push Username for 'https://github.com': <ユーザ名> <-- GitHub のユーザ名を入れる Password for 'https://sugiymki@github.com': <-- GitHub の token を入れる Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 294 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To https://github.com/sugiymki/git-tutorial.git 195ac74..885d038 feature-D -> feature-D
GitHub から確認すると, master ブランチは変更がないが, feature-D ブランチは README.md が書き換わっていることがわかる.
master ブランチは以下の通り.
feature-D ブランチは以下の通り.
現在の状況を図に表すと以下のようになる. feature-D にコミットしたので master ブランチから feature-D ブランチが分岐した.
git pull
今, 2 つ目のローカルリポジトリ (~/test-remote/git-tutorial) 以下で feature-D ブランチを修正した. しかし, 最初から利用してきた 1 つ目の ローカルリポジトリ (~/git-tutorial) 以下には先の修正は反映されていない. このような場合はどうすれば良いだろうか?
現在の状況は下図に当てはめると, 開発者 B のローカルリポジトリと GitHub のリモートリポジトリは feature-D ブランチが master ブランチから分岐したことを知っているが, 開発者 A のローカルリポジトリはそのことを知らない, ということになる. 開発者 A のローカルリポジトリにリモートリポジトリの feature-D ブランチの最新データを 持って来たいというのが現在の問題意識である.
別の開発者が commit した内容を反映させる (= ブランチを最新の 状態にする) ためのコマンドが git pull である. git pull は git fetch と git merge を同時に行うコマンドである (git fetch と git merge について調べるのは課題で).
まず cd コマンドで元のリポジトリに移動し, 現在のブランチを確認する.
$ cd ~/git-tutorial $ git branch feature-A * feature-D fix-B master
feature-D ブランチであることを確認してから, git pull を実行する. README.md の中身が変更されていること (リモートリポジトリの最新版に置き換えられたこと) を確認する.
$ cat README.md Git tutorial It's Git tutorial test (feature-A) test (fix-B) $ git pull origin feature-D remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), done. From https://github.com/sugiymki/git-tutorial * branch feature-D -> FETCH_HEAD 195ac74..885d038 feature-D -> origin/feature-D Updating 195ac74..885d038 Fast-forward README.md | 5 +++++ 1 file changed, 5 insertions(+) $ cat README.md Git tutorial It's Git tutorial test (feature-A) test (fix-B) test (feature-D)
開発フロー: GitHub flow
多人数が同じブランチで作業をすると, コンフリクトが起きやすくなる. 特に開発者全員が master ブランチを使う状況では, 常に他の開発者のことを意識せねばならず, かえって開発の効率が悪くなることがある.
このような状況が起きにくくなるように, Git ではいくつかの標準的な使い方 (開発フロー) が提案されている. ここでは GitHub 社が実践しているシンプルなワークフローである GitHub flow をごく限定的に説明する. GitHub flow の実践は来週行う. また, 全容や詳細を知りたい場合は <URL:https://gist.github.com/Gab-km/3705015> (日本語) を参照されたい.
Git flow の鉄則は,
- 永続的なブランチは master のみ.
- 新作業は master ブランチから新ブランチを作成してから行う.
- 作成した新ブランチに修正/追加をコミットする.
- 新ブランチは最終的には master ブランチにマージする (pull request する).
ことである. 新機能の追加でもバグ修正でも必ず作業用のブランチ (「feature ブランチ」や「トピックスブランチ」と呼ぶ) を作り, そのブランチで作業する. ブランチ名は行う具体的な作業名になっていることが望ましい. ここで注意すべきは, 1 つの作業を 1 つのブランチで行うことである.
例えば,
1) コードのインデントが崩れていたので修正
2) 英単語にスペルミスがあったので修正
3) 新たなメソッドを追加
という 3 つの作業を行いたい場合は, これらをまとめて 1 つの ブランチで行うのではなく, それぞれを別々のブランチで行うべきである. 他の開発者のためにも, 修正・追加の意図が伝わりやすいように, コミットの粒度に気をつけるべきである.
この開発フローではマスターブランチ以外は作業中のブランチとなるため, 気軽に作業中のブランチを push することができる. 定期的に GitHub などのリモートリポジトリに push すると良い.
課題
以下の課題を実行し,提出物 (1)--(4) を提出すること.
課題 1
- Ruby などの任意の言語でプログラムを作成し, それを master ブランチに git commit しなさい.
commit するのはプログラム完成後である必要はない. プログラム製作の途中途中で最低 2 回は commit すること.
- リポジトリは, git-tutorial を使うこと.
- 提出物(1):git log --graph の実行結果. ターミナル上で git log --graph を実行し, それを wbt のオンラインテキストにコピペする.
- プログラム:fizzbuzz プログラム (C 言語版) を Ruby などの C 言語以外の言語に書き換えること.
課題 2
- 上記で作成したプログラム
git-tutorial リポジトリの master ブランチに登録した後,それを GitHub の同リポジトリに push せよ.
- 提出物(2):GitHub 上のプログラムを Web ブラウザで表示し, そのスクリーンショット (png, jpg, ...) を wbt に登録せよ. 但し,スクリーンショットに URL が入るようにすること.
課題 3
- 上記で作成したプログラムの修正を行う.
feature ブランチ (トピックスブランチ) を切ってから作業すること.
fizzbuzz プログラムを作成している場合には,追加内容は「7 の倍数の時は git と言う」とする.
- 提出物(3):GitHub 上の修正したプログラムを Web ブラウザで表示し, そのスクリーンショット (png, jpg, ...) を wbt に登録せよ.
- 参考: 作業手順の例
- feature ブランチを作成. ブランチ名は fizzbuzz プログラムの修正であることが分かりやすくなる名前とすること.
- feature ブランチにうつり, fizzbuzz プログラムを修正.
- 修正後, git add, git commit を実行.
- その後, master ブランチに feature ブランチを git merge する.
- ローカルのリポジトリの master ブランチを, GitHub 上のリポジトリの master ブランチに push する.
- 自分の Web GitHub をブラウザで表示し, 変更点が反映されていることを確かめる.
課題 4
- 提出物(4) : 以下を調べた結果を電子ファイルで提出せよ.
- Git における HEAD とは一体何か?
- "git push origin master" コマンドが何を意味するか答えよ.
- "git clone","git fetch","git pull" の 3 つのコマンドの違いを説明せよ.
- "git checkout SHA1","git reset SHA1","git revert SHA1" の 3 つのコマンドの違いを説明せよ.
課題 5
- 以下のライセンスの特徴をまとめよ.
- LGPL
- GPL
- AGPL
- MIT/X11
- BSD-2-Clause (二条項)
- BSD-3-Clause (三条項)
- Apache2.0