どぼじょのIT学習ブログ

高専卒土木女子がIT業界を目指してお勉強。

Git入門 part4 / タグ, コミット

本日もサルでもわかるGit入門の発展編の続きをやっていきます〜!

目次

1.発展編

1-1. タグ

コミットを参照しやすくするために、コミットに名前を付けることができます。
この名前をタグと言い、どのコミットかわかりやすいように任意の名前を付けることができます😊

Gitでは以下の2種類のタグが使用できます。

できること 軽量タグ 注釈付きタグ
名前を付ける
コメントを付ける ×
署名を付ける ×

一般的には、軽量タグはローカルで一時的に使用するような、使い捨てタグとして使用されます。注釈付きタグは、リリース用のタグとして使われます💡
また、一度付けたタグは位置が移動することがなく、固定されます。

1-2. チュートリアル タグ

前準備

タグを作るチュートリアルをやっていきます💪
まずはtutorialというディレクトリを作って、リポジトリを作成するところから!
このあたりはGit入門 part1で解説しているとおりです。
f:id:mistyrinth:20190108151617p:plain
リポジトリを作成し、myfile.txtの中に以下の1文を書いてコミットしました😊

サルでもわかるGit入門

軽量タグを追加する

まずは簡単な軽量タグから!🔖
現在のHEADが指しているコミットに軽量タグを追加するには、tagコマンドを使用します。

$ git tag タグ名

今回はappleというタグを付けます🍎
ちなみに、タグ名を指定せずにtagコマンドを実行することで、タグの一覧を表示できます。
また、履歴の一覧を表示するlogコマンドに--decorateオプションを付けて実行すると、タグ情報を含めた履歴を表示することができます😇
f:id:mistyrinth:20190108153408p:plain

注釈付きタグを追加する

現在のHEADが指しているコミットに注釈付きタグを追加するには、tagコマンドに-aオプションを指定します。
実行するとテキストエディタが起動するので、タグに設定するコメントを入力します✍️
-mオプションを指定して、直接コメントを与えることもできます。
また、tagコマンドに-nオプションを指定すると、タグの一覧とコメントを表示できます🔍

$ git tag -a タグ名

ここではbananaという注釈付きタグを付けます🍌
f:id:mistyrinth:20190108153559p:plain

タグを削除する

作成したタグを削除するには、tagコマンドに-dオプションを指定します!
f:id:mistyrinth:20190108153858p:plain

タグは簡単でしたね〜🥳🥳🥳

1-3. コミットの書き換え

コミットを書き換える方法として、以下のようなものが挙げられます。

コマンド 用途
commit --amend 同じブランチの直前のコミットに対し、内容の追加やコメントの修正を行う
※amend は commit コマンドのオプション
revert 指定したコミットの内容を打ち消すコミットを作成する
コミットが公開済みで削除できない場合にrevertが使われる
reset 不要なコミットを削除する
※詳細は下記
cherry-pick 別のブランチにある指定したコミットをコピーし、現在のブランチに取り込む
rebase -i コミットの書き換え、入れ替え、削除、統合を行う
※ i はrebase コマンドのオプション
merge --squash 指定のブランチのコミット全てをまとめたコミットを追加する
※ squash は merge コマンドのオプション

resetコマンドについては前回の記事でかなり雑に扱ってしまいましたが、改めて学習します!
参考にしたのはこちらのサイトです🙋‍♀️

www-creators.com

resetコマンドの用途は以下の2つです。

- 用途1:インデックスを任意の状態にリセットする
- 用途2:ブランチの先頭`HEAD`を指定したコミットに強制移動する

また、resetコマンドのオプションには、--soft--hardがあります。内容は以下のとおりです😊

モード オプション 解説
mixed 無し(default) HEADの位置を戻したい場所に移動してインデックスを更新するが、作業ツリーはそのままにする
soft --soft HEADの位置を戻したい場所に移動するが、インデックスと作業ツリーはそのままにする
hard --hard HEADの位置を戻し、インデックスも作業ツリーも丸ごとリセットする

1-4. チュートリアル コミットの書き換え

以上を踏まえ、チュートリアルを進めます🏃‍♂️

commit --amend

予め履歴が用意されているローカルリポジトリを使ってチュートリアルを行います。
ダウンロードはチュートリアルページの始めのほうにリンクがあります✨
stepup-tutorialというファイルがダウンロードされるので、私はデスクトップに置いてアクセスすることにします。(もちろんどこでもいいです)
f:id:mistyrinth:20190108160502p:plain
キャプチャのように、stepup-tutorialの中にはtutorial1からtutorial7までのディレクトリが保存されています。
まずはtutorial1に移動し、リポジトリの履歴をチェックしたところ、既に2回コミットがされていますね👀
1回目がfirst commit、2回目がaddの説明を追加と書いてある部分です。

早速commit --amendを行います!これは直前のコミットの内容の追加やコメントの修正を行うオプションですよ🙌

tutorial1には予めsample.txtが保存されているので、中身を確認すると、以下の2行が書かれています。

サルでもわかるGitコマンド
add 変更をインデックスに登録する

前回のコミットでは、addコマンドの説明(2行目)を追加したことがわかりましたね。
ここに3行目を記載するのですが、commit --amendを使って、前回のコミットで2〜3行目を同時に追加したことにします😎
3行目の内容は以下のとおりです。

commit インデックスの状態を記録する 

一連の流れを以下に貼り付けます。
f:id:mistyrinth:20190108161757p:plain

最後のgit commit --amendを実行すると、エディタが起動し、コメントの編集ができます。
キャプチャはこちら👇
f:id:mistyrinth:20190108162336p:plain
1行目のaddaddとcommitに書き換えます!😆
f:id:mistyrinth:20190108162551p:plain
これでエディタを閉じると、コミットの書き換えが行われます🙃
そして再度logコマンドで履歴を確認すると、最初に現れた内容と変わっているため、前回のコミットが書き換えられていることが確認できますね🎉🎉

revert

次に、コミットの内容を打ち消すコミットを作成するrevertコマンドを使います。
ディレクトリはtutorial2に移動します👣
ひとまずtutorial2の中身と履歴を確認していきます。

f:id:mistyrinth:20190108163757p:plain

tutorial2の中身はsample.txtですね👀
コミットは4つあることと、sample.txtの中身は3行であることがわかります。
最初のコミットの後、1行ずつ追加してコミットしていったのですね〜🧚‍♀️

revertコマンドを使って打ち消すコミットの内容は「pullの説明の追加」にします。
最新のコミットなので、HEADが指しているところにあたりますね😊

f:id:mistyrinth:20190108164900p:plain

revertコマンドを実行すると、エディタが起動します。キャプチャは以下のとおりです📷
f:id:mistyrinth:20190108164949p:plain
これは特に修正する必要がないので、このまま閉じました🙂
logコマンドで履歴を確認すると、revertの履歴が追加されました!
sample.txtを開くと、pullの説明がなくなっています。
これが「コミットの内容を打ち消すコミットを作成する」ということなんですね💪

reset

今度はtutorial3ディレクトリを使って、resetコマンドをやってみます!
最初はtutorial3の中身と履歴を確認します。

f:id:mistyrinth:20190108200943p:plain

tutorial2と同様、tutorial3の中身はsample.txtだけですね。
コミットは4つあることと、sample.txtの中身は4行であることがわかります。

チュートリアルでは、resetコマンドを使ってmasterブランチの先頭から2つ分のコミットを削除します。

先程挙げたresetコマンドのオプションをおさらいします👀

モード オプション 解説
mixed 無し(default) HEADの位置を戻したい場所に移動してインデックスを更新するが、作業ツリーはそのままにする
soft --soft HEADの位置を戻したい場所に移動するが、インデックスと作業ツリーはそのままにする
hard --hard HEADの位置を戻し、インデックスも作業ツリーも丸ごとリセットする

masterブランチの先頭から2つ分のコミットを削除」ということは、--hardオプションがつきます!
また、HEAD(masterブランチの先頭)から2つ前はHEAD~~と書いて表すことができます。
参考記事:Git入門 pert3 / ブランチ

つまり実行するコマンドはgit reset --hard HEAD~~になります💪

f:id:mistyrinth:20190108202847p:plain

sample.txtの中身は、commit と pull の説明がなくなっていますね👌 logコマンドで履歴を確認すると、コミットが削除されていることが一目瞭然です。
--headオプションなので、ツリーごと削除してしまいました😊

ちなみに、間違えてresetしてしまった場合などは、resetコマンドでORIG_HEADという名前のブランチに reset することで、 reset 前の状態に戻すことができます。

cherry-pick

次にtutorial4ディレクトリを使って、cherry-pickコマンドをやります。
cherry-pickとは、別のブランチにある指定したコミットをコピーし、現在のブランチに取り込むコマンドでしたね🍒
これまでと同様、まずtutorial4の中身と履歴を確認します。

f:id:mistyrinth:20190108205500p:plain

tutorial4も中身はsample.txtだけです。
コミットは3つあり、sample.txtの中身は3行です。
また、最後にbranchコマンドで確認したとおり、今はissue1というブランチにいます!
このissue1ブランチで行った「commitの説明の追加」という変更をmasterブランチに取り込みます。

まずmasterブランチにチェックアウトします。
次に「commitの説明を追加」したコミットのコミットIDを指定してcherry-pickコマンドを使うことで、コミットを取り出し、masterに追加します。

コミットIDは上のキャプチャでいう99daed25b45fcae2ce9d707a3434951cf69f253aですね🧐
長すぎるのですが、全部入力しなくても、最初の数文字だけで大丈夫みたいです✨

f:id:mistyrinth:20190108214430p:plain

cherry-pickコマンドを行ったときに競合が発生したため、sample.txtを修正してからコミットしました😆
また、最後にコミットした時に表示されたエディタでは、コメントを編集できました。
このあたりはcommit --amendのときと同じなので割愛します。

rebase -i でコミットをまとめる

今度はtutorial5rebase -iチュートリアルを進めます。
rebase -iは、コミットの書き換え、入れ替え、削除、統合を行うコマンドでした。
tutorial5ではsample.txtの中身は触らないため、中身の確認はしません🙃
logコマンドで履歴の確認をします。

f:id:mistyrinth:20190108215337p:plain

コミットが4つありますね👀
ここでrebase -iコマンドを使って、HEADから2つめ(HEAD~~)の「pullの説明を追加」以降の変更をひとつのコミットに統合します!

f:id:mistyrinth:20190108220659p:plain

rebase -iを実行すると、HEADからHEAD~~までのコミットがエディタで表示されます。
f:id:mistyrinth:20190108220749p:plain
この2行目先頭のpicksquashに書き換えます🖋押し込めるという意味ですね💡
f:id:mistyrinth:20190108220923p:plain
この状態で保存すると、統合した後のコミットに設定するメッセージがエディタで表示されます。
必要に応じて編集し、保存します。私は編集せずそのまま保存しました🙂
f:id:mistyrinth:20190108221148p:plain

以上で、2つのコミットが1つのコミットに統合されました🎉🎉
logコマンドで履歴を確認します。
f:id:mistyrinth:20190108221517p:plain
3つめのコミットに、元々2つだったコミットが統合されていますね☀️

rebase -i でコミットを修正する

先程と同じくrebase -iコマンドですが、今度はコミットを修正する方法です。
tutorial6を使います。

f:id:mistyrinth:20190108221847p:plain

既にコミットが4つあります。
ここでは、HEADから2つめの「commitの説明を追加」で行った変更内容を修正します✍️
手順は途中まで先程のtutorial5と同様で、まずはrebase -i HEAD~~を実行します。

f:id:mistyrinth:20190108223356p:plain

途中で現れる別画面エディタはこちらです。
f:id:mistyrinth:20190108222529p:plain

rebase -i HEAD~~コマンドを実行すると、エディタに HEAD から HEAD~~ までのコミットが表示されます。
先程と異なるのは、今度は1行目先頭のpickeditに変更して保存するところです😊
エディタを終了すると、修正したいコミットがチェックアウトされた状態になります。
その状態でsample.txtを修正します\(^^)/
ここからは少しだけチュートリアルと進みが異なるのですが、 私は文章の一番最後に顔文字\(^^)/を付け足しました。

f:id:mistyrinth:20190109195858p:plain

rebase -i HEAD~~を実行したときに現れるエディタは以下のとおりです。
※私が\(^^)/を書き加えています💡
f:id:mistyrinth:20190109195450p:plain

チュートリアルと違うのは、私の場合HEAD~~を編集してHEAD~(Pullの説明)と競合してしまうところです。
チュートリアルでは競合が発生しないようにHEAD~の内容を書き足しているのですが、私にはちょっとわかりにくかったので自分なりにやってみます笑
私の場合だと、rebase --continue実行時に競合が発生していますね🙂

ここからはチュートリアルから少し逸れてしまいますが、競合が発生したら、sample.txtに書かれているコンフリクトを見て修正し、再度addrebase --continueを実行します。
この際、commit --amendは行いません✋
競合を解消した後には必要ないですね😊

f:id:mistyrinth:20190109200747p:plain

最後のrebase --continueで現れるエディタの内容はこちらです。
f:id:mistyrinth:20190109201126p:plain
これはそのまま編集せずに保存・終了しました😎

ちなみに途中で出てくるstatusコマンドは、前回のコミットと比較してどのファイルが変更されたか表示されます。
競合発生時にもやっておけば見比べられて良かったのですが、競合解消後と最後しかやってなくてすみません…笑

merge --squash

最後はtutorial7を使ってmerge --squash`コマンドをやってみます!
これは「指定のブランチのコミット全てをまとめたコミットを追加する」というものでした。

まずtutorial7に移動し、現状の履歴をlogコマンドで確認します。 f:id:mistyrinth:20190108233726p:plain

3つのコミットがあることが分かりますね🙂それから、今はissue1ブランチにいます。
ここからmasterブランチにチェックアウトし、merge --squashコマンドを実行することで、issue1のコミットを全てまとめてmasterの新規コミットを作成できます✨✨

f:id:mistyrinth:20190108235150p:plain
競合が発生したため、sample.txtを開いて競合を解消しました💡
競合を解消したら、コミットしていきます。
f:id:mistyrinth:20190108235544p:plain

issue1ブランチのすべてのコミットを1つにまとめたコミットがmasterブランチに追加されましたね😆😆

発展編は以上です〜!次回はPull request編!😊

Git入門 part3 / ブランチ

サルでもわかるGit入門の発展編に突入です!
入門編の記事は、part1part2があります😊

目次

1.発展編

1-1. ブランチ

ブランチとは 

Git入門 part2で少しだけ登場したブランチというものを学習します。
ブランチ(branch)は英語のとおり、履歴の流れを枝のように分岐して記録していくためのものです🌲
ブランチは他のブランチの影響を受けないため、同じリポジトリ中で複数の変更を並行して進めることができます。
また、ブランチは他のブランチと合流(マージ)し、ひとつのブランチとなることもできます🤝
そのためソフトウェア開発において、各担当者が別々のブランチでそれぞれ作業を行い、最後にマージしてひとつのソフトウェアとすることが可能になります✨
リポジトリに最初のコミットを行うときはmasterという名前のブランチが作成されます。
それ以降のコミットは、ブランチを切り替えるまでmasterブランチに追加されていきます。

ブランチとの運用方法

ブランチの運用方法についてはおそらくチームごとに決めるのですが、今回は統合ブランチトピックブランチの2つを使った運用方法について学習します💡

統合ブランチは、リリース版をいつでも作成可能な状態にしておくためのブランチです。
通常、masterブランチを統合ブランチとして使用するようです😗
トピックブランチは、機能追加やバグ修正など、ある課題に関する作業を行うためのブランチです。
統合ブランチから課題に関するトピックブランチを作成し、トピックブランチでの作業が完了したら、統合ブランチに取り込むという使い方をします。
芯となる統合ブランチがあることで、情報がごちゃごちゃしなくて良いですね😊

ブランチの切り替え

作業するブランチを切り替える操作をチェックアウトと言います。
また、現在使用しているブランチの先頭のことをHEADと表します。このHEADが移動することで、作業するブランチが変更される仕組みです💡

コミットを指定するときに、この時にHEADと後述の記号を組み合わせて、あるコミットからの相対位置で指定することもできます。

記号 読み方 用途
~ チルダ 何世代前の親かを指定する
^ キャレット 何番目の親かを指定する

使い方のイメージは以下のような感じです😊凡例を書き忘れてしまったのですが、葉っぱはコミットです。
f:id:mistyrinth:20181224124710p:plain

変更内容をコミットしていないままチェックアウトを行うと、その変更内容はワークツリーやインデックスに残ったまま、移動先のブランチに移ります。
ただし、移動先のブランチで既にそのファイルに変更が行われている場合、チェックアウトに失敗してしまいます💦
このような場合に、一時的に変更内容を退避させてからチェックアウトする方法があります。
stashという、ファイルの変更内容を一時的に記録しておく領域を使い、ワークツリーとインデックス内にあるコミットされていない変更を、一時的に退避させることができます!
また、退避させた変更は後から取り出して、元のブランチや別のブランチに反映させることができます👏

ブランチの統合

トピックブランチでの作業が完了したら、最終的に統合ブランチに統合されます。
ブランチを統合する方法として、mergeを使う方法と、rebaseを使う方法の2種類があります。
どちらを使うかによって、統合後のブランチの履歴が大きく異なるそうなので、しっかり学習しておきます😎

方法 特徴
merge ・各々の変更履歴を統合する
・変更内容の履歴がそのまま残る
・履歴が複雑になる
rebase ・それぞれのコミットで競合を解消し、履歴を一本化する
・元のコミットの変更履歴が変わる
・履歴は単純になる

図で表すと以下のようになります。
f:id:mistyrinth:20181226171143p:plain

うーん分かりにくい…😶笑
チュートリアルに進んでみましょう!!

1-2. チュートリアル1 ブランチを使ってみよう

早速チュートリアルに沿って進めていきます🚗

前準備

まずはtutorialディレクトリを作って、空のリポジトリを作成します。

$ mkdir tutorial
$ cd tutorial
$ git init

次にmyfile.txtというファイルを作成し、サルでもわかるGitコマンドというテキストを入力してコミットします。

今回からコンソールの入力/出力の表示を変えました〜!
今までは枠で囲ってたのですが、沢山続くと見にくいのでマーカーにしました😊
f:id:mistyrinth:20181226175741p:plain

ブランチを作成する

早速、branchコマンドを使ってissue1という名前のブランチを作成します。

$ git branch ブランチ名

また、branchコマンドで引数を指定しない場合、ブランチ一覧を表示します。
*が付いているのが、現在のブランチです🌲

f:id:mistyrinth:20181226180718p:plain
今はmasterブランチにいますが、他にissue1ブランチがあることが確認できますね✨

ブランチを切り替える

issue1ブランチにコミットを追加していくには、checkoutコマンドを使ってissue1ブランチをチェックアウトします😊
宿泊施設のチェックアウトとは違って指定したブランチを出るのではなく、指定したブランチに切り替えるコマンドです!

$ git checkout ブランチ名

ここではブランチ名はissue1になります👆
f:id:mistyrinth:20181226183838p:plain

ちなみに、以下のようにcheckoutコマンドに-bオプションを付けると、ブランチの新規作成とチェックアウトを同時に行えます✨

$ git checkout -b ブランチ名

続いて、myfile.txtの中身に2行目を追加してコミットします🙂

f:id:mistyrinth:20181226184228p:plain

ブランチをマージする

先程issue1で行った変更をmasterブランチに merge します。
まずはcheckoutコマンドでmasterブランチに移動します。

$ git checkout master

f:id:mistyrinth:20190107160646p:plain

myfile.txtの編集はissue1ブランチ上で行ったため、masterブランチのほうでは内容は変更されていないことが確認できます。

ブランチのmerge はmergeコマンドで実行できます😊

$ git merge 取り込みたいブランチ名

このコマンドを実行すると、指定したブランチがHEADの指しているブランチに取り込まれます!

f:id:mistyrinth:20190107161431p:plain

masterブランチのコミットがissue1と同じ位置(HEAD)に移動しました👌
このマージはfast-forward(早送り)マージと呼ばれます。 遅れているmasterブランチのコミットをさくっとissue1と同じコミットの位置まで持ってくることができるので、早送りと言われるんでしょうね😶

ブランチを削除する

issue1ブランチの内容はmasterブランチに無事統合されたため不要になりました。
issue1ブランチを削除します!
ブランチの削除は、branchコマンドに-dオプションを指定して実行します。

$ git branch -d ブランチ名

f:id:mistyrinth:20190107162252p:plain
branchコマンドでブランチの一覧を確認すると、issue1が削除されているのがわかります🎉

並行で作業する

今度は、2つのブランチで並行で作業してみます!
まずissue2ブランチとissue3ブランチを作成し、issue2ブランチをチェックアウトします。

f:id:mistyrinth:20190107162911p:plain

まずはissue2ブランチ側の作業です!
myfile.txtcommitコマンドの説明を追加してコミットします。
f:id:mistyrinth:20190107163334p:plain

一方、issue3ブランチのmyfile.txtにはpullコマンドの説明を追加します👀
issue3ブランチをチェックアウトし、myfile.txtpullコマンドの説明を追加してコミットします。

f:id:mistyrinth:20190107164028p:plain
これでissue2issue3masterに統合しようとすると、衝突が起きますね…!💥

マージでの衝突を解決する

いよいよ、issue2ブランチとissue3ブランチそれぞれでの変更をmasterブランチに統合します💪
まず、masterブランチをチェックアウトして、issue2ブランチを merge します。

f:id:mistyrinth:20190107164912p:plain

ここでは何の問題も無くfast-forwardマージが行われますね🙂
続いて、issue3ブランチをmasterブランチにマージします。

f:id:mistyrinth:20190107165408p:plain

自動マージに失敗し、myfile.txtには競合箇所が示されています。
前回のおさらいですが、競合箇所の読み方は以下のとおりです!

<<<<<<<
現在チェックアウトしている側の内容(ここではmasterブランチ)
=======
競合相手の内容(ここではissue3ブランチ)
>>>>>>>

これを受け、myfile.txtを以下のように修正します✍️

サルでもわかるGitコマンド
add 変更をインデックスに登録する
commit インデックスの状態を記録する
pull リモートリポジトリの内容を取得する

修正したら、改めてコミットします。
f:id:mistyrinth:20190107180928p:plain
出てくる文字が少ないですが、エラーではないので、たぶんOKだと思います!笑

今回の merge では、競合箇所を修正して、その変更を記録するマージコミットが作成されました。そこにmasterの先頭が移動していることになります🚗
このようにfast-forwardではないマージは、non fast-forwardマージと呼ばれます😂

rebaseでマージする

先程issue3ブランチをマージする際にissue3ブランチを rebase したら、履歴を一本にすることができました💡
rebase のチュートリアルをやってみます🙌
まずは一旦、resetコマンドの--hardオプションで先程行ったマージを取り消します!
resetコマンドはそれだけで結構書ける内容なので、ここでは解説を割愛して以下のコマンドをそのまま実行します。

$ git reset --hard HEAD~

resetコマンドについて詳しくは以下のブログを拝見しました!わかりやすかったです😊

git reset コマンドの使い方と、主要オプションまとめ | WWWクリエイターズ

実行するとこんな感じになります。
f:id:mistyrinth:20190107184018p:plain

これで現状issue2masterブランチにマージ済みで、これからissue3ブランチをマージするところまで戻りました!
ここでissue3ブランチをチェックアウトし、masterブランチに対して rebase を実行します!

f:id:mistyrinth:20190107184349p:plain

やはりmyfile.txtで競合が発生するため、mergeの時と同じmyfile.txtを修正します。
myfile.txtの中身は先程と全く同じなので、修正も割愛します〜👣

競合箇所を修正したら、rebase の場合にはコミットではなく、rebaseコマンドに--continueオプションを指定して実行します。
これにより、masterブランチはissue3ブランチをfast-forwardマージできるようになります✨
masterブランチをチェックアウトしてマージを実行します。

f:id:mistyrinth:20190107185913p:plain
mergeと比べて履歴(経緯)は異なりますが、myfile.txtの最終的な内容は同じです🤝

1-3. リモートリポジトリ

リモートリポジトリに対する動作として、pushやpullを学びました。
参考記事:Git入門 part1 / Gitの基本

おさらいを兼ねて、Fetchも合わせて意味を確認します!

用語 意味
Push ローカルリポジトリの履歴をリモートリポジトリにアップロードすること
Pull リモートリポジトリの履歴をローカルリポジトリにダウンロードすること
自動的にマージコミットが作成されるが、競合があれば手動で解決する
内部的に Fetch + merge をしている
Fetch マージせずにリモートリポジトリの履歴を取得すること
取得したコミットは名前の無いブランチとして作成される
(FETCH_HEADという名前でチェックアウトできる)

本日は以上です🙂

Git入門 part2 / リポジトリの共有, 変更履歴の統合

本日はサルでもわかるGit入門 リポジトリの共有から勉強していきます!
前回の記事はこちらになります。

目次

1.前回のおさらい

前回の記事では、様々な Git 用語が出てきました💡
記事の最後に用語の意味を一覧にまとめたので、おさらいとして再掲します。

用語 意味
repository データの状態を保存する場所
作業用のローカルリポジトリと共有用のリモートリポジトリがある
Push ローカルリポジトリからリモートリポジトリにアップロードすること
Pull リモートリポジトリからローカルリポジトリにダウンロードすること
commit ファイルやディレクトリの追加・変更をリポジトリに記録する操作
worktree 実際に作業をするディレクト
index リポジトリとワークツリーの間にあり、リポジトリにコミットするための準備をするところ

2.入門編

2-1. リポジトリの共有

早速サルでもわかるGit入門を進めていきます!

リポジトリとは、ファイルやディレクトリの状態を保存(コミット)しておく場所のことでしたね🙂
作業を行うためのローカルリポジトリと、他の人と共有するためのリモートリポジトリがありました。
前回の記事では、新規のローカルリポジトリを作成するところまでやったので、ここではリモートリポジトリの使い方を学びます!

Git では、ローカルリポジトリ内の変更履歴をリモートリポジトリにアップロードする操作を Push と言います。
逆に、リモートリポジトリの変更履歴をローカルリポジトリにダウンロードする操作を Pull と言います。

また、リモートリポジトリを複製する操作は、Clone と言います。
クローンを実行すると、リモートリポジトリの内容をまるまるダウンロードしてきて、別のマシンにローカルリポジトリとして作成できます👌

2-2. チュートリアル2 リポジトリの共有

チュートリアルにある「リモートリポジトリをBacklog上に作成する」というのは GUI環境でやるっぽいですね。
Backlogはどうやら有料サービスのようなので、 Github でやってみます!
Githubも非公開リポジトリを作るのは有料プランにする必要があるみたいなので、公開リポジトリにしちゃいます😊
勉強用だし、見られてもたぶん困らないでしょう笑
f:id:mistyrinth:20181222134252p:plain
何も設定されていない空のリポジトリが作成されました。名前はtutorialです。
前回の記事で作成したtutorialという名前のローカルリポジトリの履歴を、このリモートリポジトリに Push します!💪💪

Push する際に、対象のリモートリポジトリのアドレスを指定するのですが、毎回いちいちアドレスを入力しなくても済むように、アドレスに名前をつけて記録しておくことができます💡
ここではリモートリポジトリのアドレスにoriginという名前を付けて登録し、Pushを行います。
アドレスの登録にはremoteコマンドを使います👆

$ git remote add 登録名 リポジトリURL

先程Github上に作成したリモートリポジトリのURLはhttps://github.com/mistyrinth/tutorial.git です。
私の場合、以下のようになります👌
f:id:mistyrinth:20181222135637p:plain

いよいよローカルリポジトリのコミットをリモートリポジトリに Push します!
pushコマンドを使用します😊

$ git push プッシュ先URL ブランチ名

ブランチについては発展編で詳しく学習できるみたいなので、今はチュートリアルのとおり、ブランチ名をmasterにして進めてみます!
なお、空のリモートリポジトリに初めて Push するときはブランチ名を指定する必要がありますが、pushコマンドの-uオプションを指定すると、次回以降はブランチ名の指定を省略できます✨
プッシュ先URLは、先程originという名前で記録したので、originと書けばOKです!
実際にやってみました。
f:id:mistyrinth:20181222141145p:plain
成功したみたいですね〜🎉
ブラウザで Github を見てみると、空だった tutorial にsample.txtが追加されています!
前回作ったテキストファイルが反映されていますね。

今度はリモートリポジトリのクローンをしてみます😆
練習のため、先程自分で作ったリモートリポジトリをクローンします。
cloneコマンドを使用します。はリモートリポジトリのURL、は複製先のディレクトリ名を指定します。

$ git clone リモートリポジトリURL 複製先ディレクトリ

複製先ディレクトリに任意の名前を指定すると、カレントディレクトリにその名前のディレクトリ名を作って複製することができます。
ここでは複製先ディレクトリをtutorial2とします。今はtutorial2という名前のディレクトリは存在しないので、カレントディレクトリ(この場合ホームディレクトリ内のtutorial内)にtutorial2という名前のディレクトリが作成されます📁
f:id:mistyrinth:20181222142401p:plain

クローンが成功したか確認してみます。
f:id:mistyrinth:20181222143023p:plain
できました!🧸
tutorialの中にtutorial2というディレクトリが作成され、中にはsample.txtがあります。
誤解してはいけないのが、cpコマンドと同じようにローカルリポジトリ内で複製したのではなく、リモートリポジトリ(Github)から複製してきたという点ですね😊😊

更に、複製して作ったtutorial2からもリモートリポジトリに Push してみます。
tutorial2内のsample.txtに2行目を追記しました!
f:id:mistyrinth:20181222143628p:plain

前回と同じ流れで Push していきます。
振り返る場合は前回の記事をご参照ください🌝
f:id:mistyrinth:20181222145206p:plain
元々リモートリポジトリにあったものをクローンしたものなので、pushコマンドの際にPush先のURLやブランチ名は省略できました👌
Githubを見ると、tutorial2が反映されています✨
f:id:mistyrinth:20181222145433p:plain
注意点は、tutorial2の変更点をリモートリポジトリに Push したのであって、複製したわけではないということです。
Githubtutorialの中にtutorial2が入ったわけではなく、Githubtutorialtutorial2に更新した感じです💡そのため、前回からの変更点を見ることができます。

今度は、tutorial2からリモートリポジトリに Push した内容を、ローカルリポジトリであるtutorialに Pull します。
以下のようにpullコマンドを使用します。
リポジトリ名を省略すると、originの名前で登録されているリポジトリに対してpullを行います。

$ git pull リポジトリ名 参照仕様

参照仕様 (refspec) とは、この場合ブランチ名masterです。入門編のうちは、そのくらいの解釈で良いのだと思います!笑
実際に Pull を行い、正しくできているか確認を行いました。
f:id:mistyrinth:20181222160850p:plain
logコマンドで変更履歴を見ると、「addの説明を追加」という履歴が現れましたね!!これはtutorial2で行い、リモートリポジトリに Push したものなので、大成功です😆

2-3. 変更履歴の統合

今のところ一人で Push や Pull をしているので問題ありませんが、例えば、私が最後に Pull を実行してから次に Push するまでの間に別の人が Push をして、リモートリポジトリが更新されたとします。
こうなってしまうと、私は Push が拒否されてしまいます😖もし私が Push できてしまったら、せっかくの別の人の変更履歴を失ってしまうからですね。
この場合、マージという作業を行って自動的に他の変更履歴を取り込むことで、別の人による変更履歴を失わずに Push することができます🙌

ただし、リモートリポジトリ(別の人)とローカルリポジトリ(私)がたまたま同じ箇所を変更していた場合は、マージしようとしても、どちらの変更を取り込むかを自動で判断できず、エラーになります。
このように競合が発生した箇所は、エラーを見ながら手動で修正することになります💦

2-4. チュートリアル3 変更履歴の統合

競合を解決してマージする練習として、tutorialtutorial2を使ってセルフ競合してみます👣
現在、tutorialtutorial2それぞれにsample.txtが保存されており、中身はどちらも以下の2行です。

サルでもわかるGitコマンド
add 変更をインデックスに登録する

これをtutorialtutorial2で別の変更を行い、マージを試します!
それぞれ、最後の1行に次の異なる文章を追加します。

tutorial:commit インデックスの状態を記録する
tutorial2:pull リモートリポジトリの内容を取得する

以下がtutorialsample.txtの中身です。
f:id:mistyrinth:20181222155229p:plain
addコマンドでインデックスの追跡対象に登録し、commitコマンドでローカルリポジトリtutorialにコミットします。
f:id:mistyrinth:20181222155930p:plain

一方、以下がtutorial2sample.txtの中身です。
f:id:mistyrinth:20181222155259p:plain
こちらも同様にaddコマンドでインデックスの追跡対象に登録し、commitコマンドでローカルリポジトリtutorial2にコミットします。
f:id:mistyrinth:20181222160015p:plain

これらを同じリモートリポジトリに Push してみます!
まずはtutorial2のほうから。
f:id:mistyrinth:20181222160350p:plain
これにより、リモートリポジトリ側には3行目の変更履歴として pull の説明が追加されたことになりました!
f:id:mistyrinth:20181222160439p:plain
続いて、tutorialから Push してみると、競合が起きているためエラーになりました!!
f:id:mistyrinth:20181222160951p:plain

競合を解決するために、まずはエラーになってしまったtutorial側で Pull を行い、変更履歴を取得します。
f:id:mistyrinth:20181222161415p:plain
"Automatic merge failed"とのこと🔥🔥
あとは"Merge conflict in sample.txt"と書かれていますね👀
tutorialsample.txtを開いてみます!
f:id:mistyrinth:20181222161903p:plain
なんと、競合箇所を教えてくれています✨✨✨
読み方は以下のとおりです。

<<<<<<<
ローカルリポジトリ(ここでは競合により拒否されたほう)
=======
リモートリポジトリ(ここでは先に push されていたほう)
>>>>>>>

これをどう扱うか決めて、手動で解決していくこととなります。
今回は両方の変更を取り入れ、以下のように3行目に commit の説明、4行目に pull の説明がくるように編集します💪
f:id:mistyrinth:20181222162559p:plain
修正を Push に反映させるために、再度addcommitを行います。
f:id:mistyrinth:20181222163003p:plain

ここで Push の前に、logコマンドの--graphオプションと--onelineオプションを試してみます!
--graphオプションは、変更履歴の流れをテキスト表示することができます。
--onelineオプションは、コミットの情報を一行で表示します。
f:id:mistyrinth:20181222163827p:plain
logコマンドの表示から、2つの分岐が一つに統合されたことが分かります😆
無事pushは成功しました!!
f:id:mistyrinth:20181222163938p:plain
自作自演のため全部私のアイコンで一見わかりにくいのですが、tutorialをいじった人とtutorial2をいじった人が違う場合、このように履歴に残るので便利ですね〜!

Git入門編は以上です🌝

Git入門 part1 / Gitの基本

作った gem を Github に公開するために、Github の使い方を覚えておく必要があります😊
また、Github を使うために、まずは git の知識が必要になるようです。
ということで本日はサルでも分かるGit入門をやっていきます!
遠回りですみません😭😭

目次

1.入門編

1-1. Gitの基本

Git は、分散型バージョン管理システムのひとつです。
例えば社内サーバにおいて、Aさんがデータをサーバに保存し、後日Bさんが更新をして、更にCさんとDさんがそれぞれ編集して同時に更新したら、一方が消えてしまった…ということが起こりえます😖
Git では、データの状態を好きなときに更新履歴として保存して、過去の状態に戻したり、更新箇所を確認したりできるそうです!

ファイルやディレクトリの状態を保存する場所をリポジトリといいます。
状態を保存するということは、前回の保存状態との差分から、更新した内容を表示することもできます😊

リポジトリにはローカルとリモートの2つがあり、普段は個人がローカルリポジトリで作業を行い、作業が終わったら、他の人と共有するためにリモートリポジトリにファイルをアップロード(push)するということになります。
また、他の人が作成したファイルをリモートリポジトリから自分のローカルリポジトリにダウンロード(pull)することもできます。

また、ファイルやディレクトリの状態をリポジトリに記録する操作をコミットと言います。
コミットを実行すると、前回コミットした状態から現在の状態までの差分を記録したコミット(またはリビジョン)が作成されます。コミットは動詞でもあり名詞でもあるんですね〜!
また、コミットの実行時にはコミットメッセージを入力します。
Git のコミットメッセージの書き方は以下のとおりです💡

1行目 : コミットでの変更内容の要約
2行目 : 空行
3行目以降 : 変更した理由

そして、実際に作業するディレクトリをワークツリーと呼びます。
ワークツリーは Git の管理下にあり、ワークツリーとリポジトリの間にはインデックスというものがあります🔖
インデックスとは、ワークツリーで作業したファイルをリポジトリにコミットするための準備をする場所です。
コミットする時は、ワークツリーから直接リポジトリ内に状態を記録するのでなく、インデックスの設定に従って状態を記録します。
これにより、ファイル丸ごと全部をコミットしなくても部分的にコミットすることができます✨

1-2. チュートリアル1 Gitの基本

サルでも分かるGit入門チュートリアルでは、Windows, mac(GUI), コンソールから環境を選べます。わたしはコンソールで進めていきます💪
まずは Git のインストールを行います!Homebrewをインストール済みなので、以下のコマンドでインストールしました🙂

$ brew install git

念のため以下のコマンドでバージョンを確認すると、2.20.1でした👀

git -- version

f:id:mistyrinth:20181221204225p:plain

次に Git の初期設定として、ユーザ名とメールアドレスの登録を行います。
リポジトリにコミットする際、履歴などに表示されるそうです😊

$ git config --global user.name "ユーザ名"
$ git config --global user.email "メールアドレス"

合わせてチュートリアルに従い、Gitの出力をカラーリングする設定と、checkoutコマンドに対するcoというエイリアスの作成をしました!

$ git config --global color.ui auto
$ git config --global alias.co checkout

コンソールの場合、コマンドでも設定変更できますが、設定ファイルを直接編集することもできます。
ホームディレクトリにある.gitconfigを開いてみました!
f:id:mistyrinth:20181221210820p:plain
先程の設定が反映されていますね😆

続いて、新規ローカルリポジトリの作成です。
ローカルリポジトリの新規作成は、リポジトリという特別なものを作るのではなくて、mkdirディレクトリを作成して、そのディレクトリをリポジトリに指定するという流れです。
ここでは、ホームディレクトリにtutorialという名前のローカルリポジトリを作ります!

$ mkdir tutorial
$ cd tutorial
$ git init

f:id:mistyrinth:20181221212159p:plain
空のリポジトリができました✨✨

では、リポジトリにファイルを登録します。
まずは、先程作った tutorial ディレクトリの中にsample.txtというテキストファイルを作成します。
ファイルの中身のテキストは、チュートリアルに従いサルでもわかるGitコマンドにします。
わたしは vim で作りました!
f:id:mistyrinth:20181221213721p:plain
入力2のcatコマンドでは、ファイルの中身を確認しているだけです😶
入力3のstatusコマンドでは、Gitの管理下にあるディレクトリの、ワークツリーとインデックスの状態を確認しています💡

$ git status

ここでは tutorial ディレクトリのワークスペースとインデックスの状態を確認しています。
赤文字でsample.txtとなっているのは、インデックスによる履歴の追跡対象になっていないからです🙄
インデックスに登録すると、追跡対象に登録することができるので、インデックスに登録をします!

履歴の追跡対象としたいファイルをインデックスに登録するには、addコマンドを使用します。

$ git add ファイル名

ファイル名はスペース区切りで複数指定することができます🌝
今はsample.txtだけですね。
addコマンドでsample.txtを追加して、先程と同じくstatusコマンドを実行すると、以下のようになります。
f:id:mistyrinth:20181221214704p:plain
インデックスにsample.txtが追加され、リポジトリへのコミットの準備ができました🎉

リポジトリにコミットするにはcommitコマンドを使用します。

$ git commit -m コメント

コメントは"first commit"としておきます✍️
これでコミットができると、先程のstatusコマンドを実施しても変更履歴が無いはずですね〜☀️
また、変更履歴を確認できるlogコマンドも実行してみたので、一連のキャプチャを貼ります!
f:id:mistyrinth:20181221215603p:plain

面白いですね〜!!
複雑になってくるところを早く見てみたいです😆😆

2.用語のおさらい

今日は沢山専門用語が出てきたので、一覧にまとめました!

用語 意味
repository データの状態を保存する場所
作業用のローカルリポジトリと共有用のリモートリポジトリがある
Push ローカルリポジトリからリモートリポジトリにアップロードすること
Pull リモートリポジトリからローカルリポジトリにダウンロードすること
commit ファイルやディレクトリの追加・変更をリポジトリに記録する操作
worktree 実際に作業をするディレクト
index リポジトリとワークツリーの間にあり、リポジトリにコミットするための準備をするところ

今日は以上です😊

独自gem作成その3 / 体裁整え, README

前回の 独自gem作成では、実際のコードを書いてテスト完了し、rubocopによりraisのスタイルガイドに沿っているかチェックをしたところまでやりました🙂
本日は続きをやっていきます!

目次

1.rubocopの検証

前回の rubocop の検証では、26個のCの警告が出ているところまでやりました!
これらをひとつひとつ確認して修正していきます。

26個のCの内容と対処方法は以下のとおりです💪
重複している内容もあるので、全部で8種類でした🙂

Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.

# frozen_string_literal: trueと記載し、直後に空白の1行を入れる(出典

Style/StringLiterals: Prefer double-quoted stringsunless you need single quotes to avoid extra backslashes for escaping.

' text 'の表記を" text "に修正(出典

Style/UnneededPercentQ: Use %q only for strings that contain both single quotes and double quotes.

%q{ text }の表記を" text "に修正(出典

Style/HashSyntax: Use the new Ruby 1.9 hash syntax.

→ ハッシュの記法を Ruby1.9 以降のものに修正(出典

Layout/SpaceInsideParens: Space inside parentheses detected.

( calc )の中にある余計なスペースを削除(出典

Layout/TrailingBlankLines: Final newline missing.

→ 最終行に空白行を追加(出典

Layout/SpaceAroundOperators: Operator = should be surrounded by a single space.

=の前後に連続しているスペースを1つにする(出典

Layout/SpaceInsideBlockBraces: Space between { and | missing.

{| text | }{ の後にスペースを1つ入れる(出典

これらをひとつひとつ修正しました😊
f:id:mistyrinth:20181221163559p:plain

2.READMEを記述

公開する前に、README.mdに gem に関する情報を書いておきます。
コードではなく、人にわかるように文章を書きます💡ここに書いておくと、他の方が README を読んで、どんな gem なのか知ることができます✨
デフォルトでは以下のような状態です。
f:id:mistyrinth:20181221164109p:plain
これを自分なりに書いていきます。

ここまでできたら無事公開!のはずですが…
Githubの使い方わからないので、一旦Githubの勉強を挟みます🙏
道のりは長い😂

独自gem作成その2 / Gemの作成, RSpecテスト, rubocop

本日は具体的に gem を作っていきます!

目次

1.gemのアイデア

作る gem のアイデアですが、いろいろと考えた結果、数値を英語に変換してみようと思います!
例えば1oneに変換するやつです。
gem の名前はconv_num_wordsにします!

2.実際に作ってみる

2-1. gemテンプレートの作成

まずは以下のコマンドで gem のテンプレートを作ります。

$ bundler gem conv_num_words

作る場所はどこでも良いのですが、私はホームディレクトリにしました!
f:id:mistyrinth:20181213112058p:plain
この時点で自動的に gem に必要な沢山のファイルが作成されます。
gem は沢山のファイルによって構成されているため、IDE統合開発環境)でgem のルートディレクトリを開いたほうが作業しやすいです✨
わたしの場合は Visual Studio Code を使っています🙂
IDEを使うと、いちいちメモ帳のようなエディタを開いて編集しなくても、ディレクトリの中のファイルをツリーで確認しながら、ファイル間を行ったり来たりできるようになります!
細かくて見にくいですが、以下が IDEVisual Studio Code)の編集画面です。
f:id:mistyrinth:20181213112208p:plain
ざっくり分類分けすると、左側に gem を構成するディレクトリ、メイン部分がコードエディタ、下部にターミナルがあります👀
この画面は、次に編集するgemspecを開いているところです😊

2-2. gemspecの修正

先程の操作で自動的に作成されたファイルのうち、gemspecというファイルを編集します💪
TODO:で始まるところがダミーなので、そこに自分の情報に置き換えます。
とは言っても description などは作っているうちに変わりそうなので、とりあえず今はTODO:を取り外したり、ソースコードURLをコメントアウトにして、後で編集し直すことにします🤗

2-3. 実際のコードを記述

テンプレート作りが終わったので、今度は実際にコードを書いていきます。
数値を英文字に変換するという同じ発想の方がいらっしゃったので、かなり参考にさせていただきました!

d.hatena.ne.jp

コードを書くのはlib/conv_num_words.rbの中です。
f:id:mistyrinth:20181217192721p:plain
Numericクラスを拡張していく形で変換前後を定義していきます。
21以上の数は大変なので、桁(hundred, thousand)ごとに計算式を書きます✍️
f:id:mistyrinth:20181217192901p:plain

2-4. ビルドして実行

コードが書けたら、ビルドしてみます!
ビルドのためにまずexeファイルを作成する必要があります。
gemのルートディレクトリで以下のコマンドを実行します。

$ mkdir exe
$ touch exe/conv_num_words
$ chmod +x exe/conv_num_words

この一連の流れは、1行目でexeディレクトリを作り、2行目でその中にconv_num_wordsというファイルを作り、3行目でconv_num_wordsの実行権限を付与しています💡 次に、以下のコマンドを実行してビルドします。

$ bundle exec rake build

f:id:mistyrinth:20181214143746p:plain
このあたり参考にしたページのリンクを載せておきます👏
qiita.com

続いて、gemをインストールします!

$ gem install pkg/conv_num_words-0.1.0.gem

f:id:mistyrinth:20181214144114p:plain

ここで確認のため、 irb を起動してrequire'gem名'を実行してtrue`になると良いです👌
エラーが出たら修正して、再ビルドして再インストールです😊😊
私は修正したきり再ビルドせずに irb を繰り返して何度も同じエラーを見ていながら、修正が反映されないことに気づくのが遅かったです笑

2-6. テスト

次に、spec/conv_num_words_spec.rbを編集します。
RSpecを使ってテストを行います。
f:id:mistyrinth:20181217200217p:plain
上のキャプチャは、conv_num_wordsのNumericクラスに対して、to_wを使ったときに予測できる変換前後を述べています。
テスト名(テストが成功したときに表示される名前)をconvert number into wordsにしています。
一応全ての通りの組み合わせがテストできるように書いてみたつもりですが、見落としがあったらご指摘ください😶
テストを書いたら、ターミナルで以下のコマンドを実行します👆

$ bundler exec rspec spec

※コマンドがbundlerだったりbundleだったりぶれてしまい申し訳ありません。どちらでも良いようです笑
f:id:mistyrinth:20181217201248p:plain
テスト完了です!
ここで予測した答えと実際の答えが一致しないと、以下のように丁寧に教えてくれます。
f:id:mistyrinth:20181217201453p:plain

2-7. rubocopで検証

ここまできたらもうパッケージ化して公開ですが、その前にひとつ確認しておくことがあります🤨
それは Ruby のコードはスタイルガイドに則っているか?ということです。
コードが正しくても、インデントがめちゃくちゃだと見にくいので、Rubyのスタイルガイドに合わせて書き直す必要があります。

github.com
このスタイルガイドに則って書けているか確認する rubocop というものを試してみます。
rubocop が未インストールの場合は以下のコマンドでインストールします。

$ gem install rubocop

使い方は簡単で、チェックしたいコードが書かれているファイルがあるディレクトリに移動し、rubocopを実行するだけです。
私の場合はホームディレクトリに作っているconv_num_wordsというディレクトリに移動してrubocopを実行します☀️
ただし、はじめはrails本家の設定にするために一手間加えます🙂
まずは対象のディレクトリに移動し、.rubocop.ymlというファイルを作成します。
f:id:mistyrinth:20181217202705p:plain
とりあえずtouchで作成しました!ls -aで作成できたことが確認できますね〜🌝
もちろん、IDEのほうでも確認できます。というかIDEで編集します。
rails本家のrubocop.ymlファイルが公開されているので、これを作成したファイルの中身に反映させます✨

github.com

こんな感じになります。
f:id:mistyrinth:20181217203154p:plain
いよいよターミナルで以下のコマンドを実行してみます!

$ rubocop

すると、長々とメッセージが現れます。
f:id:mistyrinth:20181217203722p:plain
黄色のCの文字が目立ちますね👀
このアルファベットは、見つかった違反の種類を指しています。
違反の重要度が重い順にFatal, Error, Warning, Conventionがあります。
メッセージに現れるCは一番軽い違反を教えてくれています。 最後の1行には、8 files inspected, 26 offenses detectedと書かれており、26個の違反が見つかったことが分かります🙄
f:id:mistyrinth:20181217203905p:plain
これを修正してから、パッケージ化をして公開、という手順を踏んでいきます。

さて、これをひとつひとつ確認して修正していくのは次回で!笑

独自gem作成その1 / bundler

本日からは、独自の gem を作ることを目標にいろいろ学習を進めていきます!
gem についてはこちらの記事で少し触れていますのでご参照ください✨

目次

1.gem 作成前の下準備

独自の gem はまだ思いついていないので、まずはRubyGemsの公式ページを読んでみます。

Guides - RubyGems Guides

目次の順番に読んでいき、MAKE YOUR OWN GEMを読み始めてみると、bundler で gem を作るというリンクがあります💡
ちょっと寄り道してリンク先の bundler のページを見てみると、bundler 1.13で gem を作る解説ページに飛びます👀
私のパソコンにインストールされている bundler のバージョンは 1.17.1 なので、1.17の解説ページを読むことにしました😊

Bundler: How to create a Ruby gem with Bundler

私のパソコンには bundler がいつの間にかインストールされています。というか、過去にインストールした記憶はあるのですが、なぜだったか思い出せません笑
なのでインストール手順は飛ばして、以下のコマンドでバージョンの確認をします。

$ bundler -v

f:id:mistyrinth:20181204102428p:plain
バージョンは 1.17.1 です💡
ちなみに bundler 未インストールの場合、以下のコマンドでインストールできます。

$ gem install bundler

2.bundler で gem を作る練習

2-1. Getting Started

先程の bundler のサイトに gem を作る例が載っているので、まずはそれに従ってやってみます。
bundler で新しく gem を作るには、まず以下のコマンドを実行します。

$ bundler gem 作りたいgem名

ここではfoodieという名前の gem を作ってみます!

We call our gem foodie because this gem is going to do a couple of things around food, such as portraying them as either “Delicious!” or “Gross!”. Stay tuned.

どうやら food に対してDilicious!Gross! のどちらか反応をするための gem っぽいですね🙂

bundler gem foodieを実行すると、3つの質問をされます。
f:id:mistyrinth:20181204110643p:plain

どれも今は正直分からないので、テストファイルはよく見かけるほうのrspecにしておいて、それ以外はyesとしておきます。

無事にfoodieという gem が作れたみたいです!
f:id:mistyrinth:20181204113109p:plain
ホームディレクトリにfoodieというファイルができたみたいです!これが gem ですね😊
f:id:mistyrinth:20181204113436p:plain
foodieの中にも様々なファイルが作成されています。
ターミナル操作は大変になってくるので、ここからは必要に応じてVSCodeで作業します😗

2-2. Testing our gem

VSCodefoodieを開いてみると、ファイルが作成されているのがより分かりやすくなります。
次のキャプチャはfoodieの中のfoodie.gemspecを開いている様子です。authors や homepage などダミーの文字列が入っていますが、正しく入力しないと進めないので、適当に入力して、飛ばしたいところはコメントアウトしていきます😐笑
f:id:mistyrinth:20181204142135p:plain

次にbundle installを実行します。ここでエラーがあると、先程のダミーがまだどこかに残っている可能性があります💀
エラー文が丁寧に教えてくれるので、読んだとおりに対処すれば解決は難しくないと思います。
f:id:mistyrinth:20181204162436p:plain

bundlerのページを読み進めていくと、foodie_spec.rbに書く内容が載っているので、コピペしてみます。
f:id:mistyrinth:20181204161528p:plain
foodie_spec.rbには元々何か書かれているのでそれはそのままにして、# added by sayaka以下がコピペ文章になります。
ちなみにコピペそのままだと 17行目でdescribeが Object に定義されていないというエラーが起きてしまうので、ここは元々書いてあるコードの真似をして冒頭にRSpec.を付け足しています⛄️
コードを見ると、どうやらブロッコリーが不味いみたいですね😂笑
bundler exec rspec specを実行します。
f:id:mistyrinth:20181204162727p:plain
テスト成功です🎉🎉

2-3. Using other gems

続いて、自分の gem から Active Support のpluralizeメソッドを使うとのことですが、なんのこっちゃという感じですね〜🙃
解説を読んだところ、activesupportという gem を指しているのだと思いますが、pluralizeは今のところ謎です。
それっぽいリンクは見つかりました!笑

Method: String#pluralize — Documentation for activesupport (5.2.1)

今は言われるがままに進めてみましょう💪💪
他の gem を使うには、foodie.gemspecに使いたい gem を関連付けます。
activesupportへの紐付けをfoodie.gemspecの44行目に書いてみました。
f:id:mistyrinth:20181204181718p:plain
次に、再びbundle installを行います。これでactivesupportという gem がインストールされるはずです✨
実行画面では分からなかったので、gem listコマンドを実行し、インストール済みの gem 一覧を見てみました。
f:id:mistyrinth:20181204180103p:plain
activesupportが正しくインストールされていることが確認できました🙂
次はfood_spec.rbdescribe Foodie::Foodブロック内にpluralizeのテストを作成します。
f:id:mistyrinth:20181204180735p:plain
上のキャプチャでいう26〜28行目です!
最後に、doof.rbの先頭にrequire 'active_support/inflector'を追加し、foodクラスの中にpluralizeメソッド(14〜16行目)を定義します。
以上で Active Support のpluralizeメソッドが使えるようになったはずなので、テストしてみます!
f:id:mistyrinth:20181204182344p:plain
テストは成功…っぽいですが、pluralizes a wordという出力で合っているんでしょうか…笑
てっきりfoodie.spec.rbで設定したtomatoesが出力されると思っていたのですが😐
仕組みがまだ分からない以上なんとも言えませんが、とりあえず本日はここまで!