1 概要・連絡
1.1 小テスト❻
- 小テストを実施します。筆記用具を準備しておいてください。
1.2 達成目標
- Git管理しているフォルダを任意の過去状態に戻すことができる。
- GitHub で「コラボレータ」の追加設定ができる。
- チーム開発の場面において Git/GitHub の「ブランチ」を効果的に利用できる。
2 前回の復習・定着確認
- Git
によるバージョン管理を開始するためには対象のプロジェクトフォルダに移動し、そこで
git initコマンドを実行する。これにより、プロジェクトフォルダのなかに.gitという隠しフォルダが作成される。- Git によるバージョン管理をやめたい場合は、この隠しフォルダを削除すればよい。
- Git Bash などの Linux互換環境で
lsコマンド実行時に、隠しファイルや隠しフォルダを表示するためには-aオプションを付けてlsを実行する。 - Git
管理されているプロジェクトフォルダにおいて、カレントフォルダ以下に存在するすべての変更ファイルを
ステージング するためには
git add .コマンドあるいはgit add --allコマンドを実行する。 - Git 管理されているプロジェクトフォルダにおいて「first
commit」というメッセージをつけて コミット
するためには
git commit -m "first commit"のようにコマンドを実行する。 git remote add origin https://github.com/zzzz/Test.gitのようにコマンドを実行すると、GitHub 上のリモートリポジトリ (https://github.com/zzzz/Test123.git) を originというショートカットネームで扱えるようになる。- 「ローカルリポジトリの
mainブランチ」を「リモートリポジトリ (origin) のmainブランチ 」に プッシュ するためにはgit push origin mainのようにコマンドを実行すればよい。この際 -u オプションをつけると、以降、ローカルリポジトリのmainブランチにいるときはgit pushだけでgit push origin mainに相当する プッシュ ができる。 - リモートリポジトリの内容をローカルリポジトリに
プル する (取り込む) ための
git pullコマンドはgit fetchコマンドと git merge コマンドを組み合わせた操作である。 git clone https://github.com/zzzz/Test123.gitのようにコマンドを実行すると カレントフォルダ にTest123というフォルダが新規作成され、その内部にリポジトリが展開される。- もし
Test456というフォルダにローカルリポジトリを展開したい場合はgit clone https://github.com/zzzz/Test123.git Test456のようにコマンドを実行すればよい。
- もし
3 拡張機能のインストール
Git を利用したバージョン管理に役立つ「VSCode の拡張機能」として次の 2 つをインストールしてください。
3.1 Git Graph
Git Graph は
「コミットグラフ」を VSCode
で表示するための拡張機能 です。VSCode
の拡張機能の検索欄に mhutchie.git-graph と入力し、Git
Graph
をインストールしてください。使い方については、今回の授業のなかで紹介します。
3.2 Auto Commit Message
Auto Commit Message は コミットメッセージを自動生成してくれる拡張機能 です。例えば、ファイルの追加や変更を読み取って「update xxx.html, yyy.css and zzz.js」や「create 3 files and update 6 files」のようなコミットメッセージを生成してくれます。
VSCode の拡張機能の検索欄に
michaelcurrin.auto-commit-msg と入力し、Auto Commit
Message インストールしてください。
Auto Commit Message のインストール後、なんらかのコミット対象が存在するときに、次のように❷ のアイコンをクリックすると、❸ のコミットメッセージのテキストボックスに、自動生成されたコミットメッセージが入力 されます。
4 プロジェクトフォルダを過去のコミット時点に戻す
ここでは Git の機能を使用してプロジェクトフォルダ (ローカルリポジトリ) を 過去の任意のコミット時点に戻す方法 について学びます。また、この機能に関して理解を深めるためにいくつかの実験をしてみます。
4.1 準備
準備として、プロジェクトフォルダに次のような変更を加えながら 4つのコミット を作成していきます。
- first commit
- フォルダの内容:(空)
- 2nd commit「README.md と aaaa.txt を追加」
- フォルダの内容:
README.md,aaaa.txt
- フォルダの内容:
- 3rd commit「bbbb.txt を追加」
- フォルダの内容:
README.md,aaaa.txt,bbbb.txt
- フォルダの内容:
- 4th commit「cccc.txt を追加」
- フォルダの内容:
README.md,aaaa.txt,bbbb.txt,cccc.txt
- フォルダの内容:
このような変更履歴の記録を作成した後、つまり「4th commit」までを完了させた後、プロジェクトフォルダを「2nd commit」の時点に巻き戻すような実験をしてみます。
以下に、実験の「準備手順」を示します。
4.1.1 「first commit」
ターミナル (Git Bash モード) を起動して
cd
コマンドを使ってドキュメントフォルダなどの適切な場所に移動します。例えば
C:\Users\xxxx\Documents などに移動します。
Git Bash でのフォルダ移動
Git Bash は Linux 互換環境 (シェル) です。そのため
cd する場合、C: などのドライブレター
(Windows特有のパス表記) を含むときは
cd "C:\Users\xxxx\Documents"
のようにダブルクォーテーションで囲むか、cd /C/Users/xxxx/Documents
のように Linux形式のファイルパス
を使用してください。
Git-Playground
というフォルダを作成し、そのフォルダ内に移動して「Git初期化」します
(Git によるバージョン管理を開始します)。 Playground
という単語は、一般には「子どもが遊ぶための場所や施設」を意味しますが、プログラミング分野では新しいアイディアや技術を試したり、実験したりするための環境やスペースを指す意味で使用されます。
$ mkdir Git-Playground
$ cd Git-Playground/
$ git init
Initialized empty Git repository in C:/Users/xxxx/Documents/Git-Playground/.git/
上記の操作により .git
という隠しフォルダが作成されたことを確認しておきます (確認には
ls -al などのコマンドを利用してください)。
また git status コマンドで現在の「git
管理の状態」を確認しておきます。
$ git status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
「On branch main」「nothing to commit」、つまり、現在は
main という初期ブランチ (デフォルトブランチ)
にいて、まだコミットが存在していない状態
であることが確認できます。
ここで main というブランチ名はGit
のインストール設定に基づいて設定されます。ブランチの概念や操作については講義後半で詳しく取り上げます。
現在の「ブランチ」を確認する確認
「現在、どのブランチにいるか」は Git Bash
の表示からも確認できます。下記の場合 main
ブランチにいることが読み取れます。
初期状態 (フォルダ内に .git 以外は存在しない状態)
で「first
commit」を作成します。フォルダが空の状態でコミットする場合には、次のように
--allow-empty
オプションを付ける必要があります
(このオプションをつけないとコミットできません)。
$ git commit --allow-empty -m "first commit"
[main (root-commit) d0e8462] first commit
git log --oneline
で「コミットの履歴」を確認します。--oneline
をつけると 1 コミットの情報が 1 行
で出力されます。以下のような応答があればコミットに成功しています。
--onlineではなく--onelineなので注意してください。
$ git log --oneline
d0e8462 (HEAD -> main) first commit
なお、上記応答の先頭にある 16進数で7桁の値 d0e8462
は コミットハッシュ
と呼ばれます。コミットハッシュは、コミットの内容やタイムスタンプに基づきSHA-1(慣例的に「シャー・ワン」と読みます)
により生成される一意な ID となります。
このため、皆さんの手元で実行したときはコミットハッシュの値は、上記の実行例と違う値になるはずです。ハッシュ値 についての概要は「情報2」の「第09回講義資料」を参照してください。
4.1.2 「2nd commit」
プロジェクトフォルダに ファイルを追加して編集をくわえるため に VSCode を起動します。
VSCode へのパスが適切に設定されていれば Git Bash から
code . & と入力することで VSCode
を起動することができます。
$ code . &
上記コマンドの末尾に & (読み方は情報 1
で習ったようにアンパサンド)
を付けずに実行すると VSCode
のウィンドウを閉じるまで Git Bash が操作できない
ので注意してください。このように &
をつけて起動することを「バックグラウンド実行」といい、Linux
操作の基本として知られているので覚えておいてください
(現在利用している Git Bash は Linux 互換環境です)。
VSCode で README.md
を新規作成して以下の内容をコピペして保存してください。ここでは、確実に「保存操作」を実行してください
(保存しないまま操作すると以降の結果が違ってくるので注意してください)。
# first commit
- フォルダの中身: (空)
# 2nd commit「README.md と aaaa.txt を追加」
- フォルダの中身: `README.md`,`aaaa.txt`VSCode のマークダウンプレビュー機能
VSCode でマークダウン形式のファイル (.md
拡張子のファイル)
を編集しているとき、下記のアイコンを押下するか、ショートカットキー
Ctrl+K,V
を入力すると「マークダウンのプレビュー表示」ができます。Ctrl+K,V
は「Ctrl」を押しながら「K」を押下、つづいて「Ctrl」を離して「V」を押下する操作です。
また、同様に aaaa.txt
というファイルも新規作成してください。このファイルの中身は空で問題ありません
(何かを記述してもよいです)。
そして README.md と aaaa.txt を
ステージング して
2nd commit「README.md と aaaa.txt を追加」
というコミットメッセージをつけて コミット
してください。これは VSCode で実行しても、Git Bash
からコマンド入力で実行してもどちらでも問題ありません。
VSCode から変更内容を「ステージング」して「コミット」する手順
左端の ソース管理 のアイコンをクリックして「ソース管理」パネルに切り替えます。
「 変更」から「」のアイコンをクリックしてファイルをステージング (=コミット対象として選択) して、テキストボックスにコミットメッセージを入力してから「 コミット」のボタンを押下します。このセクションでは GitHub は使用しないので「コミットしてプッシュ」や「コミットして同期」ではなく「コミット」を選んでください。
今後、「ステージングとコミットの操作は再解説しない」ので覚えておくようにしてください。
なお、コミットメッセージを空欄にしてコミットボタンを押下してしまったときの対応は、前回講義のファイルの作成とコミット のコラム「コミットメッセージを付けずにコミット操作をすると…」を参照してください。
コマンドライン から変更内容をステージングしてコミットする
コマンドラインからは git add --all
ですべての変更内容をステージングして、git commit -m "xxxxx"
でコミットができます。
$ git add --all
$ git commit -m "2nd commit「README.md と aaaa.txt を追加」"
git add --all
の代わりに、git add README.md aaaa.txt
のように対象となるファイルを明示的に指定しても実質的に同じ動作になります。
GitBash に戻り git log --oneline のコマンドで
コミット履歴の確認 をします
(VSCode
からコミットした場合もコマンドラインから必ず履歴の確認をしてください)。以下のようになっていれば問題ありません
(繰返しになりますがコミットハッシュの値は違っていても問題ありません)。
$ git log --oneline
9a305d1 (HEAD -> main) 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
ここで「2nd commit」のところに
(HEAD -> main)
という表記があることに着目してください
(重要)。これについての詳細は後で解説しますが「2nd
commitn」に対して main
というブランチのポインタが紐づいており、さらに
main には HEAD
というポインタが紐づいていることを意味します。ここでのポインタとは「しおり」や「ブックマーク」「目印」をイメージしてください。
このあともコミットメッセージを「3rd commit …」「4th commit …」のように続けていきますが 実務ではこのような「何番目のコミット」ようなメッセージの付け方はしないので注意してください (first commmit は例外)。いまは、後で行なう実験を分かりやすくするために、このようなコミットメッセージにしています。
4.1.3 直前のコミットを取り消す
VSCode で 直近のコミットをやり直したいとき (例えば「コミットメッセージを誤った」「変更の漏れがあった」などでコミットを取り消したいとき) は、次のように「前回のコミットを元に戻す」を選択してください。
いまは、この操作をする必要はありません
同様に
コマンドラインから直近のコミットをやり直したいとき
は、次のように git reset --soft HEAD^
を実行します。
$ git reset --soft HEAD^
ただし、VSCode の場合でも、コマンドラインの場合でも、この取り消し操作は「当該コミットをリモートリポジトリにプッシュしたあとには絶対に実行しない」ようにしてください (特にチーム開発をしている場合は絶対にしないでください)。リモートリポジトリとローカルリポジトリの履歴に不整合が生じて、その修正のためにコマンドラインを使って相当に面倒な修正が必要となります。
コミットメッセージだけの修正
直前のコミットについて「コミットメッセージだけ」を修正したい場合は、次のように
--amend をつけて git commit
を実行します。
$ git commit --amend -m "新しいコミットメッセージ"
これも、リモートリポジトリにプッシュした後には実行しないようにしてください。git 中級者になってリモートとローカルの不整合を自力で手動修正できるレベルになったら、プッシュ後に実行しても問題ありませんが・・・。
4.1.4 「3rd commit」
README.md を以下のように書き換えて保存してください
(VSCode
を使用していると保存操作を忘れることが多いです。コミット前には確実に保存してください)。また
bbbb.txt
という空ファイルをプロジェクトフォルダに追加してください。そして、README.md
と bbbb.txt を ステージング して
3rd commit「bbbb.txt を追加」
というコミットメッセージをつけて コミット
してください。
# first commit
- フォルダの中身: (空)
# 2nd commit「README.md と aaaa.txt を追加」
- フォルダの中身: `README.md`,`aaaa.txt`
# 3rd commit「bbbb.txt を追加」
- フォルダの中身: `README.md`,`aaaa.txt`,`bbbb.txt`git log --oneline で
コミット履歴の確認
をします。以下のようになっていれば問題ありません。
$ git log --oneline
3757332 (HEAD -> main) 3rd commit「bbbb.txt を追加」
9a305d1 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
ここで、さきほどまで「2nd
commit」のところにあった (HEAD -> main)
が「3rd
commit」のところに移動していることに着目してください
(=ブランチポインタ main が「3rd
commit」を指し示すようになり、HEAD
ポインタは引き続き main
を指し示していることに着目してください)。
mainブランチでコミット操作すると、そのブランチポインタ (ブランチ (枝・支流) の先端を示すブックマーク) が、その最新のコミットに移動する。mainを指し示していたHEADポインタも、mainが移動することによって結果的に最新コミットに移動している。HEADが直接的に最新コミットを指し示しているわけではなく、HEADが指し示しているのはあくまでmainというブランチポインタという点に注意。
現時点では、上記の説明がピンとこない、モヤモヤすると思いますが、以下、読み進めていくことで段々と理解できると思います。
4.1.5 「4th commit」
同様に README.md
を書き換えて保存し、cccc.txt
という空ファイルをプロジェクトフォルダに追加し、ステージング
してから 4th commit「cccc.txt を追加」
というコミットメッセージで コミット
してください。
# first commit
- フォルダの中身: (空)
# 2nd commit「README.md と aaaa.txt を追加」
- フォルダの中身: `README.md`,`aaaa.txt`
# 3rd commit「bbbb.txt を追加」
- フォルダの中身: `README.md`,`aaaa.txt`,`bbbb.txt`
# 4th commit「cccc.txt を追加」
- フォルダの中身: `README.md`,`aaaa.txt`,`bbbb.txt`,`cccc.txt`git log --oneline で
コミット履歴の確認 をします。
$ git log --oneline
15c7ee4 (HEAD -> main) 4th commit「cccc.txt を追加」
3757332 3rd commit「bbbb.txt を追加」
9a305d1 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
ここでは「4th commit」のところに
(HEAD -> main)
が移動していることに着目してください。
HEAD について
HEAD というポインタ
(目印・ブックマーク・しおり) は、(HEAD -> main) や
(HEAD -> dev)、(HEAD -> bug-fix)
のように、基本的には ブランチポインタ
(ブランチの先端を示すポインタ) を指し示します。
しかし、状況によっては、以下のように HEAD
が特定のブランチポインタを指さない状態 (通称「detached
HEAD」な状態) になることもあります。
15c7ee4 (main) 4th commit「cccc.txt を追加」
3757332 3rd commit「bbbb.txt を追加」
9a305d1 (HEAD) 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
detached HEAD の状態は 特定のコミットをチェックアウトして、プロジェクトフォルダを過去の状態に戻したとき などに発生します。この状態で新たな変更を加えてコミットを追加すると、そのコミットはどのブランチにも所属しないものとなり、あとから参照することが難しくなります (もし、その状態で変更を加えてコミットする場合は、新たなブランチを作成することが推奨されます) 。このことから detached HEAD の状態での作業は慎重に行う必要があります。
4.2 GUI による変更履歴/コミットグラフの確認
コマンドラインからは git log --oneline
でコミット履歴 (変更内容を記録した履歴)
が確認できました。これは、先にインストールした Git
Graph という拡張機能を使って VSCode
からも確認ができます。実際に確認してみてください。
上記の「Git Graph
表示」が、以下の「git logの出力」と同じ情報を表していることを確認してください。Git
Graph では、中抜きの丸印が HEAD
を表しています。
15c7ee4 (HEAD -> main) 4th commit「cccc.txt を追加」
3757332 3rd commit「bbbb.txt を追加」
9a305d1 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
4.3 プロジェクトフォルダを過去の状態に戻す (Git Graph 編)
Git
はバージョン管理システムであり、プロジェクトフォルダの内容を過去の時点
(任意のコミットの時点)
に戻すことができます。例として「2nd
commit (=プロジェクトフォルダ内に README.md
と aaaa.txt だけがあった状態)」に戻してみます。
以下のスクリーンショットを参考に Git Graph のタブを表示して「戻したい時点のコミット行」をマウスでクリック選択し、その後、右クリックメニューから「Checkout…」を選択します。
作業中に「Are you sure you want to checkout commit 9a305d1a? This will result in a ‘detrached HEAD’ state. (コミット a305d1a に切り替えてもよろしいですか?これにより「detached HEAD」の状態になります)」という確認がでた場合は「Yes, checkout」を選択します。
この操作により、リポジトリ (収納庫) のなかから「選択したコミット (9a305d1a) 」を Checkoutする (チェックアウト: リポジトリから取り出し手続きする) という処理が行われます。そして、チェックアウトした内容は ワーキングツリー (=プロジェクトフォルダ) に展開されます。つまり プロジェクトフォルダの内容が「2nd commit」時点のもの に戻ります。
Git Graph ではチェックアウト操作をすると、以下のように
HEAD (=中抜きの丸印) が「2nd
commit」に移動します。プロジェクトフォルダのファイル構成が、そのコミット時点のものになっていることを確認してください。また
README.md の内容が「2nd
commit」時点の記述になっていること (ファイルの内容も過去時点に戻っていること)
も確認してください。
つづいて 最新 (=4th commit) の状態
に戻します。Git Graph の「4th
commit」のコミット行を選択し、右クリックから「Checkout…」を選択してください。ワーキングツリー
(プロジェクトフォルダ) に bbbb.txt,
cccc.txt が復活し、また README.md
の内容も最新 (=4th commit)
のものになっていることを確認してください。
このように Git管理をしていると プロジェクトフォルダの中身を過去コミット時点に戻すこと ができます。必要があれば、過去のコミットに戻した状態で、エクスプローラを使ってファイルを別フォルダに移動すること などもできます。
4.4 プロジェクトフォルダを過去の状態に戻す (コマンドライン編)
プロジェクトフォルダを過去の状態に戻す操作は、コマンドラインからは次のように実行できます。
まずは git log を使って、戻したい時点のコミットの
コミットハッシュ
を調べてメモします。ここでは「2nd
commit」の状態に戻したい (切り替えたい)
のでメモすべき値は 9a305d1 となります。
$ git log --oneline
15c7ee4 (HEAD, main) 4th commit「cccc.txt を追加」
3757332 3rd commit「bbbb.txt を追加」
9a305d1 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
次のようにコミットハッシュを引数に与えて
git checkout 9a305d1 のように
gitチェックアウトコマンド を実行します。
$ git checkout 9a305d1
Previous HEAD position was 15c7ee4 4th commit「cccc.txt を追加」
HEAD is now at 9a305d1 2nd commit「README.md と aaaa.txt を追加」最近の git (Git 2.23 以降) では checkout ではなく
git switch 9a305d1 --detach のような
gitスイッチコマンド を使うことが推奨されています
(実質的に同じコマンドです)。
$ git switch 9a305d1 --detach
HEAD is now at 9a305d1 2nd commit「README.md と aaaa.txt を追加」コマンドを実行したら、VSCode の Git Graph を確認してください。Git Graph 上でも「2nd commit」に戻っていることが確認できます (必要に応じて GitGraphタブ の右上にある「」アイコンをクリックして画面更新してください)。
ここで注意すべきは、この状態でコマンドラインから
git log --oneline
を実行したときの結果です。現時点で履歴を表示すると次のように
3rd と 4th commit
は表示されず、戻るべき「4th commit」のコミットハッシュ
が確認できません。
$ git log --oneline
9a305d1 (HEAD) 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
このようなときは git reflog --oneline (引数は
log ではなく reflog)
を実行して、そこから「4th
commit」のコミットハッシュ (=15c7ee4)
を調べて git switch 15c7ee4 --detach
のようにコマンドを打ち込んで最新の状態に戻ることができます。
$ git reflog --oneline
9a305d1 (HEAD) HEAD@{0}: checkout: moving from main to 9a305d1
15c7ee4 (main) HEAD@{1}: commit: 4th commit「cccc.txt を追加」
$ git switch 15c7ee4 --detach
Previous HEAD position was 9a305d1 2nd commit「README.md と aaaa.txt を追加」
HEAD is now at 15c7ee4 4th commit「cccc.txt を追加」
ブランチのポインタを指定してチェックアウト/スイッチ
「特定のコミット」と「ブランチのポインタ」が紐づいている場合は、そのブランチの名前を指定して
git checkout [ブランチ名] あるいは
git switch [ブランチ名]
を実行してチェックアウト/スイッチができます。
例えば、現在のケースでは以下のように main
というブランチのポインタが「4th
commit」を指し示しているので
git checkout main または git switch main
と入力して「4th
commit」に戻ることもできます。
15c7ee4 (main) 4th commit「cccc.txt を追加」
3757332 3rd commit「bbbb.txt を追加」
9a305d1 (HEAD) 2nd commit「README.md と aaaa.txt を追加」
d0e8462 first commit
4.5 コミット間の差分を確認する
Git Graph を使って、任意のコミット間の差分
(=どの部分が異なるのか)
をグラフィカルに確認することができます。ここでは、README.md
について「4th commit」と「2nd
commit」の差分 (=どこが違うのか) を確認してみます。
まずは、「新しいほうのコミット行」をクリックして選択します。
次に、Ctrl
を押下しながら「古いほうのコミット行」を選択します
(選択後は Ctrl を離してください)
。つづいて差分を確認したいファイルをクリックします。
以下のスクリーンショットのように差分を確認することができます。緑背景になっている部分が追加された行になります (ここでは該当行はありませんが、削除されている行があれば赤背景で表示されます)。なお、VSCode のウィンドウを横に十分に広げれば、「旧」と「新」を左右にならべて比較した画面で差分の確認ができます。
コマンドラインからはコミットハッシュを指定して
git diff 9a305d1 15c7ee4 -- README.md
のように差分を確認できます。差分表示には Git Graph
を使用することをお勧めします。
以上の作業が終わったら、必ず Git-Playground のプロジェクトフォルダは、削除するか、フォルダ名を変更 しておいてください。
5 GitHub を使用したチーム開発の概要
GitHub のほか、Backlog、Bitbucket のような「git リポジトリのホスティングサービス」を利用することで 複数人によるチーム開発を効率的・効果的に進めることができます。このような開発スタイルは OSS (Open Source Software) の開発はもちろん、大学の研究室や企業における実開発でも広く採用されています。
GitHub のようなリモートリポジトリは、チーム開発で チーム全員のソースコードの変更を集約・統合・管理する中心的な場所 として位置づけられることから 中央リポジトリ とも呼ばれます。
GitHubを利用したチーム開発の流れ (概要)
チーム開発では、メンバー各自が PC にローカルリポジトリを作成すると共に、GitHub などオンライン上に (1 個の) 中央リポジトリを作成し全員で「共有」します。
そして、メンバーはそれぞれのローカル環境で担当する範囲の開発を進め、ある程度、完成したものを中央リポジトリに「プッシュ (アップロード)」していきます。また、定期的に中央リポジトリから変更内容を「プル (ダウンロード)」することで、他のメンバーによる変更をローカルリポジトリに取り込みます。これを繰返すことでチーム全体でコードを共有・統合・同期しながら開発を進めます。
5.1 最もシンプルなチーム開発フロー
いつもの「アリス」と「ボブ」を例に GitHub を利用してチーム開発する際の具体的なフロー (流れ) を示します。このフローでは「フォーク」や「プルリクエスト (プルリク)」は使用せず、ブランチの機能 と コラボレータの設定 だけを利用する最もシンプルな方法を示します。
未知の用語 (ブランチ (枝・分岐・支流) やコラボレータなど) もでてきますが、まずは全体の流れを理解しましょう。
(準備・段取りフェーズ)
- アリスが「ローカルリポジトリ」を作成し、その
mainブランチに プロジェクトのスケルトン (=基盤・土台・フレームとなるプログラム) を作成します。 - アリスが、GitHub に空の「中央リポジトリ (リモートリポジトリ)」を作成し、ローカルリポジトリの内容を プッシュ (アップロード) します。
- アリスが、GitHub の設定ページからボブを「コラボレータ」として招待する手続きをします。
- ボブは招待通知のメールから GitHub にアクセスし、アリスの作成した「中央リポジトリ」に「コラボレータ」として参加することを承諾します。ボブはコラボレータとなったことで この中央リポジトリに「プッシュ」すること ができるようになります。
- ボブが「中央リポジトリ」をクローン して「ローカルリポジトリ」を作成します。
(開発編フェーズ)
- アリスとボブは、ローカルリポジトリで
mainブランチを起点に新しいブランチを作成して、その ブランチ のうえで個別に担当部分の開発をします。- ここでは、アリスが
feature/dev-aliceというブランチを作成し、ボブがfeature/dev-bobというブランチを作成するものとします。
- ここでは、アリスが
- アリスは
feature/dev-aliceで自分の担当範囲の開発を進めます。そして、その開発が完了したらmainブランチにfeature/dev-aliceブランチを マージ (取り込み) します。 - 同様に、ボブも自分の担当部分について
feature/dev-bobブランチで開発を進めます。そして、開発が完了したらmainにfeature/dev-bobを マージ します。 - アリスとボブは
定期的に「中央リポジトリ」に自分のブランチを「プッシュ」するとともに、「プル」により中央ブランチの
mainブランチにある最新の内容をローカルリポジトリに取り込みソースコードの同期と統合を図ります。
このような方法で、アリスとボブは
各自が担当範囲を並行・独立して開発しながらも、中央リポジトリの
main ブランチには
全体として統合・整合されたソースコードが
積み詰みあがっていくことになります。この手法のポイントを整理すると次のようになります。
- 中央リポジトリの管理者 (オーナー)
は、特定のメンバーを「コラボレータ」として招待することで、そのメンバーに対して
中央リポジトリへの直接的な書き込み権限
(プッシュ権限) を付与できる。
- 逆に言えば、コラボレータではないメンバーは、チーム開発に使用する中央リポジトリに対して直接的に「プッシュ」などの操作ができません。
- 各メンバーは、それぞれ ブランチ
というものを作成して、そのブランチで開発作業を進め、それが完了したら
mainブランチに マージ (反映・取り込み) するという運用をすることで、メンバーは (ある程度独立して) 開発を進めることが可能とりなり、また統合の際の コンフリクト (作業衝突) も最小限に抑えることができる。- 逆に言えば、ブランチを使用せずにチーム開発するとコンフリクト (作業衝突) が頻発して、その解決に多大な手間と時間を要することになります。
コラボレータを設定しないチーム開発
不特定多数が参加する OSS 開発などでは、開発メンバーをコラボレータに設定することなく「フォーク」と「プルリク (プルリクエスト)」という機能を使用してチーム開発する手法が採用されます。
この方式の利点は、開発に関わるメンバーが オリジナルの中央リポジトリに直接変更を加える ことなく、独立して作業を進めることができる点です。また、中央リポジトリの管理者 (オーナー や 数名のコラボレータ) は、提出されたプルリクエストをレビュー (=コードの品質や機能を確認・評価) し、品質を確保しながら変更を取り込むこと ができます。
6 コラボレータの設定
ここでは、GitHub で「コラボレータ」を設定する手順を説明します。ここでは「アリス」がオーナーの中央リポジトリに、コラボレータとして「ボブ」を参加させるという設定で説明します。
なお、ここからの操作はあとの演習で実際に体験してもらうので、いまは実行する必要はありません。解説を読んで理解するだけでOKです。
はじめに アリス側の操作 です。
GitHub にアクセスして、コラボレータとして「ボブ」をメンバーに加えたいリポジトリのページを開きます。上部にある「Settings」タブを選択して画面を切り替え、左パネルから「Collaborators」を選択します (選択後、ユーザ認証が要求される場合があります)。
初期状態では「You haven’t invited any collaborators yet (まだコラボレーターを招待していません)」となっているので、コラボレータを追加するために「Add people」ボタンを押下します。
テキストボックスに「Bob のユーザーカウント (≠ 表示名)」を入力します。
候補となるユーザーが表示されるので、そこからボブのアカウントを選択して「Add XXXX to this repository」のボタンを押下して、「ボブ」をコラボレータとして招待します。
招待の処理をすると、Bob について以下のように「Pending Invite」というステータスになります。これは、ボブ宛に招待通知が送信済みであるが、まだボブが「承認・承諾」の手続きをしていない状態であることを意味します。
ここからは ボブ側の操作 となります。
アリスがコラボレータの招待手続きをすると、ボブには以下のようなメールが届きます。メールにある「View invitation」を押下します。
なお、メッセージの意訳は次のようになります。
この招待状を承諾するか、辞退するかを選べます。また、https://github.com/ZZZZZ1980/Git-Playground にアクセスしてリポジトリを確認するか、@ZZZZZ1980 の情報を少し見て、彼らについてもっと知ることもできます。
この招待は 7 日間で期限が切れます。
GitHub のページにアクセスするのでコラボレータとして参加することを承認する場合は「Accept inviation」を押下します。なお、メッセージの意訳は次のようになります。
「Git-Playground」のオーナー (ここではアリスのこと) は以下の情報を確認できます
・あなたの公開プロフィールの情報
・このリポジトリ内での特定の活動
・リクエストが発信された国
・このリポジトリにおけるあなたの権限のレベル
・あなたの IP アドレス
再びアリス側の操作です。
当該リポジトリの「Setting」の「Collaborators」の項目を確認するとボブについて以下のような表示になっていることが確認できます。なお、ボブのコラボレータ権限を解除するためには、右端の「Remove」を選択します。
7 ブランチの利用
コラボレータを設定して GitHub を利用してチーム開発する場合、git の ブランチ という機能を利用することが (実質的には) 必須となります。
いま、「アリス」と「ボブ」の 2 名でチーム開発することを考えます。具体的には、アリスがプログラムの骨格となる「スケルトン」を作成を担当して、それに対してボブが「機能 B」の開発 (スタブの作成、実装、リファクタリング) を担当し、アリスも「機能 A」の開発を担当するという役割分担でチーム開発 (共同開発) することを考えます。
- アリス: 「スケルトン」と「機能 A」の開発を担当する
- ボブ: 「機能 B」の開発を担当する
知っておいてほしいプログラミング用語「スタブ」と「リファクタリング」
「スタブ (stub)」とはプログラミングの分野では「まだ完成していない関数やクラス、モジュール」あるいは「仮の機能しか持っていない関数やクラス、モジュール」を指す用語として使われています。例えば、関数について 実際の処理を実装する前に、関数の名前や引数、返り値の形式だけを定義した ようなものが「スタブ」と呼ばれます。
「リファクタリング (refactoring)」 とは、コードをより読みやすく、保守しやすく、再利用しやすい形に改善する作業を意味します。
7.1 ブランチを「使わないとき」と「使うとき」のコミットグラフの違い
ブランチを作成せずに、デフォルトブランチ
main で、アリスとボブが開発
(実装・コミット・プッシュ) していったときの
コミットグラフ は次のようになります。
一方で、アリスは feature/dev-alice
というブランチを作成して「機能A」を開発し、ボブは
feature/dev-bob
というブランチを作成して「機能B」を開発したときの
コミットグラフ は次のようになります。
アリスは feature/dev-alice というブランチ
(上記でマゼンタ色で表示)
で作業とコミットを繰返し、「機能A」の開発を終えたら、それを
main に取り込んでいることが分かると思います。
図から読み取れるように、ブランチを使う開発とは「
main から
feature/dev-alice
に分岐して作業を進め、それが終わったら
feature/dev-alice を
main にマージする (取り込む)
」という流れが運用の基本形になります。
7.2 ブランチを利用することのメリット
Git において ブランチ (branch) とは「枝」「分岐」「支流」といった意味で使われ 任意のコミットから分岐をつくる ことで、元のブランチや他のブランチに影響を受けず(同時に影響を与えず)に開発作業とコミットを可能にする機能です。
例えば、main ブランチの任意のコミット
(=アリスがスケルトンを作成した時点) から
feature/dev-alice と feature/dev-bob
というブランチを作成し、前者 (図中のマゼンタのブランチ)
でアリスが「機能A」の開発を行い、後者でボブ (図中の緑色のブランチ)
が「機能B」の開発を進めるとします。
このようにすることで、アリスは ボブの影響を受けずに「機能A」の開発 を進めることができます。ここで ボブの影響を受けずに開発 とは次のことを意味します。
- アリスが開発途中のコードのなかに ボブの開発途中のコード、つまり 不具合やコンパイルエラーを含むかもしれないボブのコード や あとからの大幅変更されるかもしれないボブのコード が混入することありません。
- (アリスが「機能A」を開発途中に) プッシュやプルなどの操作をしてもコンフリクトが生じない。つまり、その解消に煩わされることなく「機能A」の開発に集中すること ができます。
ブランチを使えばコンフリクトが生じないの?!
「ブランチを使えば永遠にコンフリクトが生じない」というわけではありません。アリスが「機能A」の開発を完了し
feature/dev-alice を main
にマージするとき
(下図の矢印部のように支流の変更を源流に取り込むとき)
にはコンフリクトが発生する可能性があります。
しかしながら 開発途中にプッシュやプルするたびにコンフリクトが発生して解消に追われる よりも、担当範囲の開発が完了して マージをする段階 でまとめて解消できるほうが格段に労力と時間を削減できます。
また、「機能A」の開発途中でも (必要があれば) アリスは
main を feature/dev-alice
にマージして段階的にコンフリクトを解消することができます。
7.3 mainブランチだけで開発を進めることのデメリット
アリスもボブも新たにブランチをつくることなく、デフォルトの
main
ブランチの上で開発することも技術的には可能です。しかし、この方法を選ぶと、プルやプッシュの操作をするたびにコンフリクトが発生するリスクがあります。さらに、相手の開発の途中段階のコードが随時自分の環境に組み込まれるため、作業の混乱も生じやすくなります。
例えば、下図の矢印の部分でコンフリクトが生じる可能性があります。
マゼンタ色の矢印部分はアリス側で、緑色の矢印部分はボブ側で コンフリクトが発生し、その解消をしなければならない可能性 が生じます。
基本的に、リモートリポジトリに対して「プッシュ」しようとしたとき リモート側の当該ブランチの直前のコミットが他人により行われて いると、(自分のローカルリポジトリの状態とリモートのリポジトリの内容が異なることに起因して) 以下のようにプッシュが拒否されることがあります。
Can’t push refs to remote. Tty running “Pull” first to integrate your changes.
(意訳) リモートへの「プッシュ」ができません。あなたのローカルの変更とリモートの変更が衝突している可能性があります。まずは「プル」を実行し、リモートの最新の変更をローカルに取り込んで、それを統合してから再度「プッシュ」を試してください。
この場合、まずは「プル」または「フェッチ・マージ」によってリモート側の変更をローカル側に取り込み統合 (マージ) する必要が生じます。そして、その「マージ」の過程でコンフリクトが生じる可能性があります。
一方で、feature/dev-alice
のようなブランチを作成して、そこで開発を進める場合、feature/dev-alice
というブランチに「プッシュ」するのは アリスだけ
です (運用ルールを守らずにボブが feature/dev-alice
にプッシュするようなことがあれば別ですが)
。そのため、基本的には「リモート側の当該ブランチの直前のコミット」=「自分のコミット」という状況になり、コンフリクトが起こることが無くなります。
8 ブランチを作成してチーム開発する方法
以下、2名1組による実習になります (3名1組の場合は1名は見学になります)。「アリス役」と「ボブ役」を決めて作業してください。
チーム開発のチュートリアルとして、最終的に以下のような「コミットグラフ」が形成されるような開発を体験していきます。なお、相手役の操作解説も飛ばさず読み、相手役のPCの操作画面も覗き込んで学ぶ ようにしてください。また、授業時間外には 復習として役割交代して体験 してみてください。
手順を飛ばすなどで失敗した場合は リモートリポジトリとローカルリポジトリを完全削除して、再度、最初から (コラボレータの設定から) やり直してください (やり直しのときは初回の1/3も時間がかからないと思います)。
git/GitHubは繰返し体験して慣れるしかない
git/GitHub の利用は、開発の「目的」ではなく、開発の「手段」です。そして、git/GitHub は単なる「ツール (道具)」に過ぎません。git/GitHub の内部の仕組みや細かな挙動を理解することは重要ですが、極論を言えば 使えればよい です (だって道具だもの) 。自動車でも、駆動原理を理解するより、運転できるようになることが優先されるのと同じです。
git/GitHub の習得には とにかく繰返し積極的に使用し、慣れることと、頭と手先で覚えていこと が必要です。解説を見ながらなら使えます というレベルでは不十分です。それは「教本を見ながらなら自動車を運転できます」と言っているようなものです。そんな運転者が公道で自動車を運転していたら恐ろしいですよね? 同じく、そんな git/GitHub の習練度の人が (業務レベルの) チーム開発に参加していたら恐いのです。
「この授業で解説を読みながら問題なく操作できたからOK」ではなく、授業時間外や個人開発、その他の開発活動でも積極的に使用して習得するように努めてください。
8.1 「アリス役」のステップ 1
GitHub に Git-Playground という
空のリポジトリ を作成してください
(README.md や .gitignore
を含めないでください)。公開設定は「パブリック」としてください。つづいて、前半の「コラボレータの設定」の解説に従って、ボブ役をコラボレータとして招待してください。
また、この リポジトリのURL
(https://github.com/XXXX/Git-Playground.git)
をメモしておいてください (末尾の .git
は重要なので抜けないように)。
8.2 「ボブ役」のステップ 1
前半の「コラボレータの設定」の解説に従って
コラボレータ招待を承諾
してください。また、アリスと同様に
リポジトリのURL
(https://github.com/XXXX/Git-Playground.git)
をメモしておいてください。この URL は アリスがメモしたURLと完全に同じになるはずです。
8.3 「アリス役」のステップ 2
PCのローカルストレージの適当な場所に
Git-Playground
というプロジェクトフォルダを新規作成してください。ターミナルを Git
Bash
モードで開いて、その作成したプロジェクトフォルダの中に移動してください
(pwd
コマンドなどで作成したプロジェクトフォルダの中にいることを確実に確認してください)。
以下のコマンドで「ローカルリポジトリとしての初期化」、「空状態での初期コミット」、「ローカルリポジトリに紐づける中央リモートリポジトリ
(リモートリポジトリ)
の設定」「リモートリポジトリへのプッシュ」をします。3番目のコマンドでは
https://github.com/...
の部分を先ほどのメモに置き換えてください。
$ git init
$ git commit --allow-empty -m "first commit"
$ git remote add origin https://github.com/XXXX/Git-Playground.git
$ git push -u origin main
次に VSCode を起動してください。
$ code . &
プログラムの「スケルトン」として、次の内容の
main.py を作成して保存してください。
また、プログラムが「正常実行できること」を確認してください。今回は
(pip install
による追加ライブラリのインストール予定はないので)
python -m venv .venv
で仮想環境を作成する必要はありません。なお、VSCode
で Python プログラム を実行する方法を忘れた学生は第09回の講義資料
を参照してください。
import math
# [機能A]@アリス担当 #############
# [機能B]@ボブ担当 ###############
# メイン処理 #####################
if __name__ == "__main__":
print("start.")
## 機能Aの実行
## 機能Bの実行
print("end.")次に .gitignore というファイルを作成して
、以下の内容を記述して保存してください。この
.gitignore ファイルには git/GitHub
管理をしないファイルやフォルダを記載します。例えば VSCode
のプロジェクト固有の設定を保存する .vscode
フォルダや、仮想環境を展開する .venv フォルダ、パスワードや個人的なメモを書いたファイルなどは
.gitignore に記述して git/GitHub
の管理から外します。
ここでは .gitignore
の詳細は解説しないので、詳しくは「.gitignore 書き方」などで検索してください。
VSCode から main.py と .gitignore
をステージングし、「アリスがスケルトンを作成」というコミットメッセージを付け「コミット」してください。また、その後、以下のように「プッシュ」をしてください。
Git Graph を確認すると次のようになっているはずです。
8.4 「ボブ役」のステップ 2
ターミナルを Git Bash モードで開いて
Git-Playground
というプロジェクトフォルダを作成したいフォルダに移動して開いください。
注意
「Git-Playground
フォルダを作成する」のでははなくて「Git-Playground
フォルダを作成したいフォルダに移動」してください。例えば、最終的に
C:\Users\xxxx\Documents\Git-Playground
を作成したいのなら、Git Bash のカレントフォルダが
C:\Users\xxxx\Documents
になるようにしてください。
以下のコマンドで、中央リポジトリをクローンして、Git-Playground
の中部に移動してください。最初のコマンドでは
https://github.com/...
の部分は先ほどメモしたURLに置き換えてください。
$ git clone https://github.com/XXXX/Git-Playground.git
$ cd Git-Playground/
git log --oneline
でコミット履歴を確認してください。
$ git log --oneline
91fe5c4 (HEAD -> main, origin/main, origin/HEAD) アリスがスケルトンを作成
b7d80d6 first commit
また 現在のブランチを確認するために
git branch
を実行してください。以下のような結果になります。これは、ローカルリポジトリに
main というブランチが1個だけ存在し、*
印の main
が現在のブランチであることを意味しています。
$ git branch
* main
いまからボブが「機能B」を開発するために「アリスがスケルトンを作成」というコミットを起点に feature/dev-bob
というブランチを新規作成し、そのブランチに切り替えます(スイッチします)。次のコマンドを実行してください。なお、新機能を開発するブランチには、慣例的に
feature/ というプレフィックスを付けます。
$ git branch feature/dev-bob
$ git switch feature/dev-bob
これで feature/dev-bob
というブランチが作成され、そのブランチに切り替えられたことになります。念のため
git branch で確認します。feature/dev-bob
に * 印がつき、現在はfeature/dev-bob
ブランチに切り替わっていることが確認できます。
$ git branch
* feature/dev-bob
main
実際にコードを編集して「機能B」を実装していくために VSCode を起動してください。
$ code . &
VSCode
では画面左下で「現在のブランチ」を確認できます。確かに
VSCode 上でも feature/dev-bob
に切り替わっていることを確認してください。
まずは「機能B」のスタブを作成します。main.py
を次のように編集してください
(02、08-09、19行目に編集を加えています)。また、編集したプログラムが正常に実行できることを確認してください。
import math
import datetime
# [機能A]@アリス担当 #############
# [機能B]@ボブ担当 ###############
def func_B ():
print('func_B called.')
# メイン処理 ####################
if __name__ == "__main__":
print("start.")
## 機能Aの実行
## 機能Bの実行
func_B()
print("end.")動作が確認できたら「ボブが機能Bのスタブを作成」というコミットメッセージでファイルの変更を「コミット」します。つづいて「機能B」のつくり込みをします。関数
func_B
を以下のように書き換えて動作することを確認します。
def func_B ():
t1 = datetime.datetime.now() # 現在時刻
t2 = datetime.datetime(2023,11,4,10,00,00) # 11/4 10:00
diff = t2 - t1
days = diff.days
hours= diff.seconds // 3600
print('高専祭まで、あと',end='')
print(days,end='')
print('日と',end='')
print(hours,end='')
print('時間')動作が確認できたら「ボブが機能Bを実装」というコミットメッセージで「コミット」します。その後「Branchの発行」というボタンを押下します。
8.5 「アリス役」のステップ 3
VSCode で作業します。VSCodeでは定期的に「フェッチ (中央リポジトリの内容を取得すること)」が自動実行されますが、念のために手動でも「フェッチ」をしておきます。下図のように Git Graph のタブの右上の「 雲マーク」のアイコンをクリックして、中央リポジトリの最新情報を取得します。
この結果、次のようなコミッグラフが得られます。
ボブの作業によって中央リポジトリ(origin)
のコミットは伸びていますが、中抜きの丸印で表されるアリスの
HEAD (現在コミット位置) は 「アリスがスケルトンを作成」に留まっていることが
分かります。
いまからアリスが「機能A」を開発するために、この「アリスがスケルトンを作成」というコミットを起点に feature/dev-alice
というブランチを新規作成し、そのブランチに切
り替えます(スイッチします)。さきほどは、コマンドラインからこの作業を実行しましたが、今回は
VSCode で行ってみます。
画面左下の現在のブランチを表示している部分をクリックします。画面上部にメニューが表示されるので「新しいブランチの作成…」を選択します。
新規作成するブランチの名前 feature/dev-alice
を入力して Enter を押下します。
これでブランチが作成され、それが現在のブランチになります。画面左下の表示が
feature/dev-alice
になっていることを確認してください。
VSCode で main.py
を開きます。内容が「アリスがスケルトンを作成」のコミット時点のものであることを確認してください。ボブは
feature/dev-bob
で行なわれているので、こちらは影響を受けていません。
「機能A」のスタブを作成として次のように main.py
を編集して保存し「アリスが機能Aのスタブを作成」というコミットメッセージで「コミット」します。さらに「ブランチの発行」を実行します。
import math
import fractions
# [機能A]@アリス担当 #############
def func_A ():
print('func_A called.')
# [機能B]@ボブ担当 ###############
# メイン処理 ####################
if __name__ == "__main__":
print("start.")
## 機能Aの実行
func_A()
## 機能Bの実行
print("end.")コミットグラフを確認すると次のようになっていることが確認できます。
つづいて「機能A」の実装をします。関数 func_A
を以下のように書き換え、動作することを確認します。
def func_A ():
ans = fractions.Fraction(2,3)+fractions.Fraction(4,6)
print(f'2/3 + 4/6 = {ans} (= {float(ans):.2f})') 「アリスが機能Aを実装」というコミットメッセージで「コミット」します。ソース管理パネルには、既に「ブランチの発行」を終えているので「変更の同期」が表示されます。このボタンを押下することで、中央リポジトリに「プッシュ」ができます。
現時点のコミットグラフは次のようになっているはずです。
8.6 「ボブ役」のステップ 3
VSCode で作業します。繰返しになりますが、VSCodeでは定期的に「フェッチ (中央リポジトリの内容を取得すること)」が自動実行されます。アリス役のステップ3と同様の方法で、手動で「フェッチ」して、コミットグラフを確認してください。
「機能B」のリファクタリングとして、次のように
main.py を編集して保存してください。
def func_B ():
t = datetime.datetime(2023,11,4,10,00,00) # 11/4 10:00
diff = t - datetime.datetime.now()
days = diff.days
hours= diff.seconds // 3600
print(f'高専祭まで、あと{days}日と{hours}時間')保存したら「ボブが機能Bをリファクタリング」というコミットメッセージで「コミット」を実行します。さらに「変更の同期」を実行します。なお、この「コミット」して「変更の同期」をするという操作は、コミットボタンを展開して「コミットして同期」からまとめて実行もできます。
これでボブの開発が終了したので、この
feature/dev-bob を源流の main
にマージします(取り込みます)。マージする場合は 取り込む側 (≠取り込まれる側) のブランチ
で操作します (重要ポイント) になります。
feature/dev-bob を main
にマージします。今回は、コマンドライン (Git Bash)
で実行してみます。まずは git fetch
で中央リポジトリの最新の情報を取得します。次に
git switch main で現在のブランチを main
に切り替えます。念のために git branch
で、現在のブランチが main
であることを確認します。
$ git fetch
$ git switch main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
$ git branch
feature/dev-bob
* main
次のコマンドで feature/dev-bob
ブランチを現在のブランチ(=main)
に取り込みます。--no-ff オプションをつけることで
コミットグラフ上でブランチがマージされる様子が分かりやすくなる
(明示的になる) ので付けておきます。
$ git merge feature/dev-bob --no-ff
Merge made by the 'ort' strategy.
main.py | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
コンフリクトが生じることなくマージが完了しました
(なお、コンフリクトが発生するとデフォルトエディタが起動します)。git log
で状態を確認します。マージ操作によって「Merge branch
‘feature/dev-bob’」というコミットが自動作成されたことが確認できます。
$ git log --oneline
e2ffe93 (HEAD -> main) Merge branch 'feature/dev-bob'
73d84a8 (origin/feature/dev-bob, feature/dev-bob) ボブが機能Bをリファクタリング
ecc8cfc ボブが機能Bを実装
133fdd0 ボブが機能Bのスタブを作成
91fe5c4 (origin/main, origin/HEAD) アリスがスケルトンを作成
b7d80d6 first commit
このコミットを「中央リポジトリ」にもプッシュしておきます。
$ git push -u origin main
VSCode に戻って Git Graph
からコミットグラフを確認してください。次のように feature/dev-bob が main
に取り込まれたこと が分かります。
8.7 「アリス役」のステップ 4
VSCode で作業します。念のため「フェッチ」して最新の中央リポジトリの情報を取得してください。コミットグラフは次のようになっているはずです。
HEAD を表す「中抜きの丸印」が feature/dev-bob
ブランチ先端の「アリスが機能Aを実装」コミットを指し示していること
が分かります。つまり、ワーキングツリー (=プロジェクトフォルダ)
は、feature/dev-bob
ブランチ先端の「アリスが機能Aを実装」コミット時点の構成・内容になっています
(「フェッチ」の操作をしても影響を受けていないことが確認できます)。
main.py
を開きます。「機能A」の仕上げのリファクタリングとして、次のように
main.py を編集して保存してください。
def func_A ():
f = fractions.Fraction
t1 = f(2,3)
t2 = f(4,6)
ans = t1 + t2
print(f'{t1} + {t2} = {ans} (= {float(ans):.2f})') 変更を保存したらコミットメッセージ「アリスが機能Aをリファクタリング」で「コミット」して「プッシュ」してください。これにより、現在のコミットグラフは次のようになります。
これでアリスが担当する「機能A」の開発が終了したので、この
feature/dev-alice ブランチを main
ブランチに「マージ」していきます。今度は、コマンドラインではなく
VSCode を使ってマージを実行してみます。
まずは、取り込む側のブランチである
main に切り替える必要があります。VSCode
の画面左下にある feature/dev-alice
のブランチ名をクリックして、現在のブランチを main
に切り替えてください。
現在のブランチが main
に切り替わったことで、コミットグラフの HEAD も
main のところに移動しました
(下図の矢印を参照)。しかし、現状で「中央リポジトリ
(orgin)」の main ブランチである
origin/main は、ローカルリポジトリの
main
よりも先に伸びています。よって、同期が必要で、そのために「変更の同期」のボタンを押下します。
中央リポジトリとローカルリポジトリの同期が完了すると、次のように
HEAD が main
ブランチのの先端に移動します (main
ブランチの最新のコミットに対してマージができるようになりました)。このように
マージ を行なう場合は、同期 (フェッチやプル)
によって関係するブランチを
最新の状態にしておく必要 があります。
マージ作業をはじめていきます。現在のブランチが取り込む側のである
main になっていることを再確認します (VSCode
の画面左下を参照)。つづいて、ソース管理から「ブランチをマージ」を選択します。
「マージ元のブランチの選択」として
feature/dev-alice を選択します。VSCodce
ではこのようにして main (=現在のブランチ) に
feature/dev-alice をマージ (取り込み)
する指示を与えることができます。
ここで main.py をすると
コンフリクト
が生じています。ファイル名の横の「!マーク」がコンフリクトが起きていることの通知になります。コンフリクトを解消するまではマージは完了となりません。
コンフリクトマーカーを削除して、ボブの更新も取り込むように編集して保存してください (コンフリクトの解消については前回資料を参照してください)。
以下のようなコードになれば、「機能A」も「機能B」も取り込めた状態と言えます。実際に、2つの機能が正常動作することも確認してみてください。
import math
import datetime
import fractions
# [機能A]@アリス担当 #############
def func_A ():
f = fractions.Fraction
t1 = f(2,3)
t2 = f(4,6)
ans = t1 + t2
print(f'{t1} + {t2} = {ans} (= {float(ans):.2f})')
# [機能B]@ボブ担当 ###############
def func_B ():
t = datetime.datetime(2023,11,4,10,00,00) # 11/4 10:00
diff = t - datetime.datetime.now()
days = diff.days
hours= diff.seconds // 3600
print(f'高専祭まで、あと{days}日と{hours}時間')
# メイン処理 ####################
if __name__ == "__main__":
print("start.")
## 機能Aの実行
func_A()
## 機能Bの実行
func_B()
print("end.")下図のように「変更のマージ」の項目にある
main.py
をステージングして「コミット」してください
(コミットメッセージはデフォルトのままで構いません)。その後「変更の同期」で、このマージによって更新された
main
ブランチを「プッシュ」します。
コミットグラフを確認すると次のようになっています。そして
main ブランチの最新コミット (307ab0f4)
には「機能A」と「機能B」の両方が実装された main.py
が得られます。
VSCodeの「同期」とは
VSCode の Git/GitHub 関連の機能では「コミットして同期」や「変更の同期」という用語でてきます。ここでの「同期 (Sync)」とは 「プル」操作をしてから「プッシュ」操作すること を意味します。
そのため「変更の同期」というボタンを押下することは、2段階にわけて「プル」してから「プッシュ」することと実質的に同じです。VSCodeで「プル」と「プッシュ」を単独、個別に実行したい場合は、次のように対象操作を選んでください。
8.8 「ボブ役」のステップ 4
VSCode
で「フェッチ」します。ソース管理パネルに「変更の同期」のボタンが出現するので押下します。これにより、ボブ側でも「機能A」と「機能B」の両方が実装された
main.py が得られます。
Git/GitHub を利用したチーム開発では、機能の開発は
main
ブランチの最新のコミットを起点に
feature/xxxxx
というブランチを作成して行ない、それが完了したら、そこでの変更内容を
main
ブランチにマージするという運用方法が推奨されています。この運用方法により
main
ブランチには常にリリース可能な(すなわち、正常に動作する)プログラムのバージョンを維持できるというメリットが得られます。
9 宿題 (授業時間外学習)
- ブランチを作成してチーム開発する方法 について繰返し練習してください。今回の授業で示したチュートリアルの内容は、慣れてくれば 10分 もかからずにサクサクと作業できるようになります。
- Git/GitHub
についての詳しい解説は今回で終わりです。次回以降の授業でも
Git/GitHub
は利用しますが、細かな利用法の解説はしません。この授業で扱った
git/GitHub
の知識・操作は初心者レベルの限定的なものです。より深く理解するために
YouTube や書籍で勉強してください。
- YouTube検索: Git 入門
- YouTube検索: GitHub
入門
- おすすめ書籍「やりたいことが今すぐわかる
逆引きGit入門」。
タイトルに「逆引き」とありますが、最初から順番に読み進めることもできるようになっています。コマンドライン操作を主体として、Git/GitHubの内部動作についての理解を深めたい人にはお勧めです。ただし、電子書籍版以外は残念ながら入手が難しい状況です。