連載記事一覧

連載記事一覧

当ブログで扱っている連載記事です。

Visual Studio 2017入門

terapotan.hatenablog.jp

gitをソフト開発で使いこなそう

terapotan.hatenablog.jp

回路シミュレータCircuitSimulatorAppletを使ってみよう!

terapotan.hatenablog.jp

【gitをソフト開発で使いこなそう:第7回】マージが上手くいかない!どうすればいい?

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

前回は、マージが上手くいく場面のみ解説しました。ですが実際には、マージが失敗して実行できないときがあります。
今回はマージが失敗する原因であるコンフリクトについて解説します。

更新履歴

2020年4月18日:git add --allと書くべき所を、git add -allとしていたため修正。

コンフリクトとは?

マージを行って履歴を一つにまとめる際、同じ部分が異なる内容になっていることがあります。 
この時マージを行うgitは、どちらの内容を優先すれば良いのか分からないため、マージを行うことが出来ません。(一方の内容を優先させてしまうと、もう一方の内容は失われてしまいます。)

このように、履歴が衝突することをコンフリクトと言います。

コンフリクトを説明する図

コンフリクトが起きる時

コンフリクトが起きてしまう場面を、例を挙げて見ていきます。
ブランチAとブランチB両方に、test.txtというファイルが存在しているとします。
上の文を補足する図

またtest.txtの内容は、次のようになっているとします。

test.txt(ブランチA)

あの人だーれ?
と、小さな子供が言った。

test.txt(ブランチB)

あの人だーれ?
と、私の子供が言った。

このような時ブランチAとBをマージしようとするとコンフリクトが起きます。
なぜなら、同じファイルの同じ行(test.txtの2行目)が異なる内容になっているからです。

コンフリクトを解消する

コンフリクトを解消するには、どちらの内容を残すか選んであげる必要があります。
先ほど挙げたコンフリクトの例であれば、ブランチAの内容を残すか、ブランチBの内容を残すか決める必要があります。

実際にやってみる

先ほど挙げたコンフリクトを、gitで解消してみましょう。
マージを実行したときに、コンフリクトが発生すると次のようなメッセージが表示されます。

>git merge B
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.

また、コンフリクトが発生すると、HEADが指しているブランチを表示する欄に下の画像にあるような文字が表示されます。(ブランチ名のとなりにMERGINGと表示されている。)
その画像を追加

コンフリクトが発生しているファイル(今回はtest.txt)をメモ帳などで、開くと次のように表示されます。

あの人だーれ?
<<<<<<<HEAD
と、小さな子供が言った。
=======
と、私の子供が言った。
>>>>>>>B

<<<<<<<HEADから=======の内容は、ブランチAの内容を示しており、>>>>>>>Bから=======の内容はブランチBの内容を表しています。(これらの文字は、git側で勝手に追加されます。)

どちらかの内容を消すことで、どちらの内容を残すか決めることが出来ます。
今回は、Bの内容を採用しましょう。test.txtの内容を次のように書き換えます。

あの人だーれ?
と、私の子供が言った。

どちらかの内容を消して、ファイルを上書き保存したらそのファイルをコミットします。

git add --all
git commit -m ″merge commit″

これでコンフリクトが解消されました。
先ほどブランチ名のとなりに表示されていた、MERGINGという文字も消えているはずです。

次回予告

gitでは、自分で自由にブランチを作成して運用することが出来ます。もちろんそれでも構いませんが、実はどのようにブランチを運用するか決めてあるブランチモデルというものがいくつか存在します。
次回は、ブランチモデルについて解説していきます。

う-ん、よく分からん!

この記事を読んで、疑問に思うことがあったときは、気軽にコメント欄や私のTwitterから質問してください。(すぐに答えを返せるとは限りませんが。)

参考文献

Pro Git

git,GitHubを使うにあたって必要なコマンドの使い方が詳しく解説されています。この連載を読んで分からないことや詳しく知りたいことがあったときはまずProgitを読んでみるといいでしょう。 git-scm.com

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

当サイトのプライバシーポリシー・利用規約

変更履歴

2020年3月29日:「当サイトのコンテンツについて」を追加。

用語

本プライバシーポリシーにおけるお客様とは、当サイトをご利用になる方を指します。

個人情報

個人情報とは、お客様個人に関する情報であって、当該情報を構成する氏名、メールアドレスその他記述等によりお客様個人を識別できるものをいいます。また、その情報のみでは識別出来ない場合でも、ほかの情報と容易に照合することができ、結果的にお客様個人を識別出来るものも個人情報に含まれます。

個人情報の利用目的

当サイトにおける、個人情報の利用目的は以下の通りです。

  1. 当サイトに関する問い合わせに対する回答
  2. コメントにおけるスパム・荒らしへの対応

当サイトへのコメントについて

当サイトでは、スパム・荒らしへの対応として、コメントの際に使用されたIPアドレスを記録しています。

これはブログの標準機能としてサポートされている機能で、スパム・荒らしへの対応以外にこのIPアドレスを使用することはありません。
また、次の各号に掲げる内容を含むコメントは管理人の裁量によって削除される可能性があります。

  1. 当サイトまたは第三者を誹謗中傷し、名誉を傷つける表現を含む内容
  2. 三者のプライバシーを侵害する内容
  3. ポルノ小説・写真、その他猥褻な内容
  4. 差別的表現、グロテスクな内容
  5. 法令、公序良俗に反する内容
  6. その他、不適切な内容であると管理人が判断する内容

当サイトのコンテンツについて

当サイトのコンテンツ(文章・画像等)の一部または全部を著作権法の定める範囲を超え、管理人に無断で転載することを禁じます。

個人情報の第三者への提供

原則として、お客様本人の同意を得ずに個人情報を第三者に提供しません。ただし、以下の場合は関係法令に反しない範囲で、ユーザーの同意なく個人情報を提供することがあります。

  1. 裁判所、検察庁、警察またはこれらに準じた権限を有する機関から、個人情報についての開示を求められた場合
  2. 法令により開示または提供が許容されている場合

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。
Googleアナリティクスはトラフィックデータの収集のために、Cookieを使用しています。
このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
トラフィックデータの収集は、Cookieを無効にすること等によって停止することが出来ます。具体的な設定方法については、お使いのブラウザの設定をご確認ください。

免責事項

当サイトの記載内容については、正確な記述に努めていますが、内容に対してなんらかの保証をするものではありません。当サイトの記載内容の運用は必ずお客様自身の責任と判断によって行ってください。
また記載内容の運用の結果について、当サイトはいかなる責任も負いません。

プライバシーポリシーの変更について

本プライバシーポリシーの内容は、変更されることがあります。当サイトは、内容の変更の際当サイト・SNS等を用いて、お客様に内容の変更が伝わるよう努めるものとします。
変更されたプライバシーポリシーの内容は、これらを当サイト上に掲示した後、お客様が当サイトを閲覧した時点をもって承諾されたものとみなします。

【gitをソフト開発で使いこなそう:第6回】マージって何だろう?どんな場面で使うんだろう?

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

前回は、実際のソフト開発を例にしてブランチを使う理由と使い方を解説しました。今回も実際のソフト開発を例にしてマージを使う理由と使い方を解説していきます。

「マージ」

マージとは?

今回の記事ではマージについて解説していきますが、そもそもマージとは何でしょう。

マージとは、複数のブランチの履歴をまとめる動作のことです。 例えば、今masterブランチとdevelopブランチが存在しているとします。
ブランチが二つある図

ここからdevelopブランチの履歴をmasterブランチにまとめて下の図のような状態にしたいとします。
マージ完了図

この時行われる動作がマージと呼ばれる動作です。
また図にもある通り、マージの際には二つのブランチの履歴をまとめたコミットが新しく作成されることがあります。これをマージコミットと言います。

どのような時にマージを行うのか

一方のブランチの履歴(修正箇所など)をもう一方のブランチに反映させたい時に用います。
ソフト開発を題材にして、マージを行う例を一つ挙げてみます。

上の例を簡潔に示す図
機能追加を行うために用意された、masterブランチがあります。
この状態からソフトウェアの修正を行うために、新しいブランチhotfixブランチを作成しました。

ブランチ作成

hotfixブランチでの修正が完了しましたが、このままでは機能追加を行うために追加されているmasterブランチに修正が反映されていません。
そこで、マージを行ってmasterブランチにhotfixブランチの修正の内容を反映します。

gitでマージを実行するには?

gitでマージを行う方法

gitでブランチAにブランチBをマージしたい場合は

git checkout A

を入力しブランチAに移動した後

git merge B

を実行します。
マージが正常に行われると

Merge made by the 'recursive' strategy.
 new.txt | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 new.txt

のようなメッセージが表示されます。

先ほどのhotfixブランチを使った例であれば

git checkout master
git merge hotfix

とコマンドを入力することで、hotfixブランチの修正内容をmasterブランチに反映させることが出来ます。

fast-forwardマージ

fast-forwardマージを説明する例

上の図のmasterブランチとdevelopブランチをマージすることを考えてみましょう。
下の図のようにしても、マージは出来ますが
マージコミットを使った

次のように、masterブランチを移動させるだけでもマージを行うことが出来ます。
fast-forward

developブランチを消してしまえば、あたかもmasterブランチだけにコミットをし続けてきたように見えます。

このようなマージをfast-forwardマージと呼びます。

fast-forwardのコマンドオプション

先ほどの例のように、fast-forwardマージもそうでないマージも行える場合があります。デフォルトの動作では「どちらのマージも行える場合はfast-forwardマージを優先して行い、 そうでない場合はfast-forwardでないマージを行う」となっています。
これを変更したい場合は

git merge [コマンドオプション] [ブランチ名]

git mergeコマンドの直後にコマンドオプションを置きます。
以下、使用できるコマンドオプションを紹介します。

--ff

git merge --ff [ブランチ名]

どちらのマージも行える場合はfast-forwardマージを優先して行い、 そうでない場合はfast-forwardでないマージを行います。
コマンドオプションを省略した場合、(デフォルトでは)この方針でマージが実行されます。

--no-ff

git merge --no-ff [ブランチ名]

fast-forwardマージが行える場合であっても、fast-forwardでないマージ(マージコミットを作成するマージ。)を行います。

--ff-only

git merge --ff-only [ブランチ名]

fast-forwardマージが行えない時は、マージを行いません。

fast-forwardマージのメリット・デメリット

fast-forwardマージを行うと、「マージを行った」という履歴が消えるため、履歴がシンプルになって見やすくなります。
その反面マージをどの段階で実行したのか分からなくなるため、マージを後から取り消すのは大変難しくなります。

fast-forwardでないマージのメリット・デメリット

マージコミットがマージが行われるたびに作成されるため、後でマージを取り消しやすくなります。ですが、マージの作業にそれほど意味がない場合履歴が複雑になって見にくくなる恐れがあります。

次回予告

今回挙げた例は、マージが全て「成功」する例でした。しかし、実際にはマージが「失敗」する時があります。
次回は、マージが失敗するときに起きる「コンフリクト」について解説します。

この記事について

この記事について、誤字や間違っている所がある場合は私のTwitterか、コメント欄から連絡をお願いします。

参考文献

Pro Git

git,GitHubを使うにあたって必要なコマンドの使い方が詳しく解説されています。この連載を読んで分からないことや詳しく知りたいことがあったときはまずProgitを読んでみるといいでしょう。 git-scm.com

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

【gitをソフト開発で使いこなそう:第5回】ブランチってどんな場面で使うんだろう?

次回の記事

  terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

前回ブランチはある特定のコミットを指すものと解説しました。しかし、この機能をどのような場面で活用するのかは解説していません。今回はブランチの活用方法を解説していきます。

どんな時にブランチを使うのか

ブランチを使わなかったら

ここではブランチの使用場面を理解するために次のような状況を考えてみましょう。

今あなたはgitを使ってソフトウェアを開発しています。
ソフトウェアを開発している人

ソフトウェアの開発は順調に進み何回かコミットをした後無事ソフトウェアをリリース(公開)することが出来ました。(もちろん実際のソフトウェア開発ではリリースまでに何百回のコミットが行われます。今回は例を簡単にするためにこのようにしました。)

3回目のコミットをリリース

その後あなたはリリースに機能を追加するために、ここからさらに1回コミットを行いました。

機能追加のためリリースからもう一度コミット

そんな時です。リリースしたソフトウェアを使用している方から「何かソフトがバグったぞ!修正版を出してくれ!」と言われてしまいました。

バグったぞ!修正しろ!と開発者に詰め寄るクレーマー

あなたは困ってしまいました。リリースの修正と機能追加は別々に行いたいと思っていたからです。
このままcommitDにバグの修正を入れてコミットを行いリリースしてしまうと、バグの修正だけでなく追加した機能までリリース(公開)されてしまいます。

リリース

さて、一体どうすればいいのでしょうか。

どうやってブランチを使うのか

この問題はブランチを作ることによって解決することが出来ます。

まずリリースしたコミットに予めreleaseブランチを作成しておきます。(名前はどんな名前でも構いません)

リリースしたコミットに予めreleaseブランチを作成

今回の例のようにリリースしたコミットに戻って修正したい場合、初めに以下のコマンドを実行してHEADをreleaseブランチに移動させます。

git checkout release

HEADをreleaseに移動

続いてファイルを変更しコミット(今回の例であれば不具合を修正してコミット)します。すると下の図のように履歴を分岐させることが出来ます。

履歴を分岐した時の図

上の図のような状態にしておけば、機能追加の作業に戻ることも簡単ですし(git checkout masterを実行すればよい)何回でもリリースの修正を行うことが出来ます。

ブランチを利用すれば履歴を分岐させることが出来ます。今回紹介した例以外にもブランチには様々な使われ方がありますが基本の機能は履歴を分岐させることです。

Column:ブランチはポインタだ!

前回でも何回か言った通り「ブランチはコミットを指すポインタ」です。

ブランチが履歴を分岐させるのに使われることが多いせいか、ブランチを分岐したコミットそのものと勘違いしてしまう人がいるそうです。
ブランチをそう解釈してしまうと、今後の説明がさっぱりわからなくなってしまいます。

もしブランチの意味を間違って覚えていた方はこれを機に覚えなおしてください。

もし実際にやるとしたら...?

練習のため上の例を実際のgit上で実行してみます。

まず上の例を再現するために適当なファイルを3回コミットします。
コミットを行いGitBash上でgit log --oneline --graphを入力して実行すると、次のような結果が表示されます。

* 99ff0fb (HEAD -> master) commitC
* 950c756 commitB
* fd1a78e commitA

例の通りmasterブランチがcommitCを指し、HEADがmasterブランチを指していることが分かります。
HEADがmasterブランチを指していることを確認した上で、git branch releaseを実行しreleaseブランチを新たに作成します。
git log --oneline --graphを実行すると、確かにcommitCを指すreleaseブランチが作成されていることが分かります。

* 99ff0fb (HEAD -> master, release) commitC
* 950c756 commitB
* fd1a78e commitA

HEADがmasterを指している状態のまま、適当なファイルをコミットします。
再度git log --oneline --graphを実行すると次のようになってcommitDがコミットされていることがわかります。

* 7f31df0 (HEAD -> master) commitD
* 99ff0fb (release) commitC
* 950c756 commitB
* fd1a78e commitA

上の例では、このタイミングで「リリースの修正をしろ!」と言われていました。
HEADをreleaseブランチに移動させればリリースの修正を行うことが出来ます。
次のコマンドを実行しましょう。

git checkout release

処理の結果を確認すると下のようになります。

* 99ff0fb (HEAD -> release) commitC
* 950c756 commitB
* fd1a78e commitA

(結果を見るとcommitDがありません。「commitDが消えてしまったのではないか」と思われるかもしれませんが、実際にはそうではなくただ結果に表示されていないだけです。git checkout masterを実行すると再度commitDが結果に表示されます。)

本来の開発であればここでリリースの修正を行いますが、今回は例であるため適当なファイルを追加してコミットします。
処理結果は次の通りです。

* f022dd9 (HEAD -> release) commitE
* 99ff0fb commitC
* 950c756 commitB
* fd1a78e commitA

リリースの修正が終わりました。機能開発に戻りたい場合はgit checkout masterを実行します。

* 7f31df0 (HEAD -> master) commitD
* 99ff0fb commitC
* 950c756 commitB
* fd1a78e commitA

ブランチをgit checkoutコマンドで切り替えるだけで機能開発とリリース修正を行ったりきたりすることが出来るようになりました。

Column:'detached HEAD'...?

今まで挙げた例では、HEADは必ずブランチを指していましたが 「git checkout [コミットID]」というコマンドを実行することで、[コミットID]のコミットをHEADが直接指す状態にすることが出来ます。(HEADがこのような状態になっていることをdetached HEADといいます)

今回までに解説したようなgitの使い方ではdetached HEADは意図的に起こさない限り、そう起こりませんがより高度なコマンド・操作を行うようになってくると意図せずdetached HEADになってしまうことがあります。

detached HEADの状態のまま放っておくことは好ましくありません。なぜなら、コミットを指すものがHEADしかないためHEADを別のブランチに移動させるとどのポインタ(HEAD,ブランチ)からも参照されていないコミットが発生してしまうからです。このようなコミットは一定期間経つとgitによって削除されてしまう可能性があります。

gitではHEADの移動時にdetached HEADが発生した場合「You are in 'detached HEAD' state....」から始まる警告メッセージが表示されるようになっています。

次回予告

次回は二つのブランチの履歴をまとめる「マージ」について解説します。

この記事について

この記事について、誤字や間違っている所がある場合は私のTwitterか、コメント欄から連絡をお願いします。

参考文献

Pro Git

Git,GitHubの使い方について、非常に詳しく丁寧に解説されています。
ですが、内容が初心者には難しいと思われるため一度入門記事等を読んで一通りGit,Githubを勉強してから読まれると理解が深まると思います。
pdf形式であれば、日本語版が無料で公開されています。 git-scm.com

次回の記事

  terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

【gitをソフト開発で使いこなそう:第4回】HEADって何だ?どこで使うんだ?

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

修正

2020/02/11:コラム「黒い矢印、逆じゃない?」を追加。

コミットはどのように保存されているか

今回は、ブランチについて解説していきます。 ですがその前にgitでコミットがどのように保存されているかを見ていくことにします。

Column:以降の説明について

以降のコミットの保持方法は分かりやすさを優先しているため、厳密には正しくない部分があります。
厳密な正しい格納方法を知りたい方は、参考文献にあるPro gitの「第10章Gitの内側」をご覧ください。

コミットの「名前」を見てみる

前回作成したリポジトリでGit Bashを開き次のコマンドを実行してください。

git log

すると次のように表示されるはずです。(usernameとmailAddressにはあなたが設定した値が入ります。)

commit 83b72c742842c720a090a11d7ca6430beb1952ca (HEAD -> master)
Author: username <mailAddress>
Date:   Thu Nov 14 22:05:21 2019 +0900

    test.cとtest.hを変更

commit 1fbbcb0643cbc3abfeda3756acd76c4a87557ecd
Author: username  <mailAddress>
Date:   Thu Nov 14 22:03:35 2019 +0900

    commit message

上の出力結果を見ると次のような文字列が何回も表示されているのが分かります。

83b72c742842c720a090a11d7ca6430beb1952ca

これは各コミットに割り当てられた名前を表します。 これを使って特定のコミットを指定することができます。

コミットはどのように保存されている?

コミットは下の図のように保存されています。

コミット保存方法の説明

コミットを行うとコミット(上の図でいうcommit)が作成されます。コミットの中には上の図にもある通りコミットされた時点でのファイルの情報が格納されています。
各コミットには、ひとつ前のコミットの名前が保存されています。
これを使って前に行われたコミットをたどることが出来ます。

Column:黒い矢印、逆じゃない?

上の図を見るとリンクを表す黒い矢印は、右から左に書かれています。
時間の流れ的に言えば、矢印は左から右のほうがいい気がします。
矢印の向きが逆に見えるのは、黒い矢印がコミットからコミットへのリンク(つながり)を表しているからです。

ブランチって何だろう?

Gitにおけるブランチとはコミットを指すもの(ポインタ)のことです。
下の図を見てみましょう。

ブランチとコミットの説明

図中では「master」と「develop」がブランチで、それぞれBとCのコミットを指しています。
masterブランチを指している「HEAD」は現在いるブランチを指す特殊なポインタです。

ブランチをコマンドで見てみる

前回作成したリポジトリで以下のコマンドを実行してください。

git log --oneline --graph

すると以下のような実行結果が得られます。(細かい箇所は違っていても構いません)

* 83b72c7 (HEAD -> master) test.cとtest.hを変更
* 1fbbcb0 commit message

fb1e81f...と書いてある行一つが一つのコミットを表します。同じ行に書かれているHEAD -> masterがHEADがmasterブランチを指していることを表しています。

現在のブランチとコミット

ブランチを新たに作成する

ブランチを新たに作成するには、以下のコマンドを実行します。

git branch <追加するブランチの名前>

ここでは、例として前回作成したリポジトリにdevelopブランチを作成してみましょう。
次のコマンドを実行します。

git branch develop

コマンドが実行されたら続いて次のコマンドを実行します。

git log --oneline --graph

新たにdevelopブランチが作成されていることが分かります。

developブランチ作成後

続いてHEADがmasterブランチを指していることを確認した上で、適当にファイルを追加してコミットしてみましょう。(今回はadd.txtを追加しました)

git add --all
git commit -m “add commit“

実行が完了したら再度次のコマンドを実行し、ブランチとコミットの関係が下の図のようになっていることを確認してください。

git log --oneline --graph

masterブランチコミット後

HEADを移動する(ブランチを切り替える)

本記事の最初の方にHEADのことを「現在いるブランチを指す特殊なポインタ」と解説しましたが、このHEADを別のブランチに移動させるとどうなるのでしょうか。
HEADを別のブランチに移動させるには、次のコマンドを実行します。

git checkout <移動するブランチ名>

HEADが指しているブランチは、以下のコマンドでも見ることが出来ます。HEADが指しているブランチ名の横にアスタリスクマークが着きます。

git branch
  develop
* master

今回は、developブランチへHEADを移動させるため以下のコマンドを実行します。

git checkout develop

実行した後gitで管理しているフォルダの中身を見てみると先ほど追加したファイル(add.txt)が消えていることが分かります。

HEADを別のブランチに移動させると、フォルダの中身がそのブランチが指しているコミットの内容に変わることを覚えておいてください。(HEADを移動したことによってファイル構成がAからBに変わりました。)

HEAD移動でフォルダ内容変化

次回予告

次回は、今回解説したブランチを実際の開発でどのように使うか解説します。

この記事について

この記事について、誤字や間違っている所がある場合は私のTwitterか、コメント欄から連絡をお願いします。

参考文献

Pro Git

Git,GitHubの使い方について、非常に詳しく丁寧に解説されています。
ですが、内容が初心者には難しいと思われるため一度入門記事等を読んで一通りGit,Githubを勉強してから読まれると理解が深まると思います。
pdf形式であれば、日本語版が無料で公開されています。 git-scm.com

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp

【gitをソフト開発で使いこなそう:第3回】ファイルの変更をどうやってgitに記録する?

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

前回は、Gitの導入方法について解説しました。
今回は、Gitを実際に使うにあたって必要不可欠な「ファイルの変更をGitに追加する」方法を学びます。

追記

2020/02/02:git statusについての説明を追加。

ファイルの変更を記録するには?

ファイルの変更をGitに保存する場合、

  1. ファイルの内容を変更する
  2. その時点でのファイルの状態をGitに保存する

という手順を踏む必要があります。このうち2の操作をコミットと言います。

alt

ここで注意が必要なのは、Gitはファイルの差分を記録しているのではなくコミットが行われた時点でのファイル全てを記録しているという点です。(効率化のために変更がないファイルは、上の図にある通り前のコミットへのリンクが追加されます。)
このような構造にすることでブランチ(次回解説します。)の作成を高速に行うことが出来ます。

実際にコミットしてみる

以上のことを踏まえて、実際にコミットを行ってみましょう。

リポジトリの作成

リポジトリを作成します。
空のフォルダを新しく作成し(場所はどこでもよい)GitBashを開きます。
そこで、以下のコマンドを入力します。

git init

リポジトリの作成に成功すると以下のようなメッセージが表示されます。

Initialized empty Git repository in <フォルダ名>

ファイルを追加する

今回は、ソフト開発を想定して以下の2つのソースコードを追加します。
main.c,test.hを先ほど作成したフォルダに作成し、以下の内容を追加してください。

main.c
#include<stdio.h>

int main(void){
    printf("%d",add(1,2));
    return 0;
}
test.h
#ifndef TEST_H
#define TEST_H

int add(int,int);

#endif
test.c
#include "test.h"

int add(int a,int b){
    return a + b;
}

コミットする

以下のコマンドを続けて入力します。

git add --all
git commit -m "commit message"

前者のコマンドの意味は、後程解説します。

後者のコマンドでコミットを行います。各コミットには、コミットメッセージと呼ばれるコミットの内容について説明した文を付けることが出来ます。
コミットメッセージは上のコマンドのように、git commit -m "<コミットメッセージ>"とするとつけることが出来ます。

コミットされているか確認する

以下のコマンドを入力すると、今まで行ったコミットが全て表示されます。

git log
commit fb1e8f0021f40e0efd065633694c12b2c3b6c719 (HEAD -> master)
Author: username <mailAddress>
Date:   Sun Oct 6 17:25:44 2019 +0900

    commit message

commit,Author(コミットを行った人物。第二回で登録したユーザ名とメールアドレスが表示される),Date(コミットを行った日付)の下にコミットメッセージが表示されているのがわかります。今回は、コミットメッセージにcommit messageを指定したためcommit messageと表示されています。

Column:分かりやすいコミットメッセージを付ける

先ほども解説した通り、コミットメッセージはコミットの内容を解説したものです。わかりやすいコミットメッセージをつけることによってどのコミットでどのような変更が行われたかが、分かりやすくなります。

どのようなコミットメッセージをつけるかは基本的に自由ですが、普通次のようにします。

  • 1行目に変更内容の概要を書く
  • 2行目は空行にする
  • 3行目に変更の理由を書く
複数行のコミットメッセージを入力するには、「git commit -F- << EOM」と入力します。
「git commit -F- << EOM」と入力すると、複数行入力するためのプロンプトが表示されます。入力を終了したい場合は「EOM」と入力してください。

ステージングエリアって何?

この記事の冒頭で、ファイルの変更をGitに記録するステップを次のように解説しました。

  1. ファイルの内容を変更する
  2. その時点でのファイルの状態をGitに保存する

ですが、実際には1と2のステップの間に以下の操作が入ります。

  • コミットするファイルをある領域に追加する

Gitでは、変更された全てのファイルを変更するのではなくある領域に追加されたファイルだけをコミットします。
このある領域のことをステージングエリアと呼びます。ステージングエリアに追加するファイルを指定することで、「このファイルはコミットせずに、あのファイルだけコミットする」といったことが可能になります。

実際にやってみる

ステージングエリアについてより深く理解するために、実際にステージングエリアを使用してみましょう。
使用するリポジトリは先ほど使用したもので構いません。

新たにDocument.txtを追加し、test.c,test.hを以下の内容に変更してください。

Document.txt
add関数は、与えられた二つの数を加算した数を返します。
sub関数は、(後でsub関数の説明を書く。)
test.h
#ifndef TEST_H
#define TEST_H

int add(int,int);
int sub(int,int);
#endif
test.c
#include "test.h"

int add(int a,int b){
    return a + b;
}

int sub(int a,int b){
    return a - b;
}

ここで、「Document.txtは書きかけだからコミットしたくないが、とりあえずtest.cとtest.hだけコミットしたい」という場合を考えてみます。
このような場合test.cとtest.hだけステージングエリアに追加する必要があります。
test.cとtest.hをステージングエリアに追加するには、次のコマンドを入力します。

git add test.c test.h

この状態で以下のコマンドを入力し、実行するとtest.cとtest.hのみコミットされます。

git commit -m "test.cとtest.hを変更"

git status

git statusコマンドを使うと、どのファイルが変更されているのか、どのファイルがステージングエリアにあるのか、どのファイルが新たに追加されたのかを調べることが出来ます。

簡単な例を一つ挙げてみましょう。
test2.txt、test.txt、test3.txtがあってそれぞれ

  1. test2.txt:ステージングエリアにあるファイル
  2. test.txt:ステージングエリアに追加されていない、変更されたファイル
  3. test3.txt:新たに追加されたファイル

であるとします。
ここで

git status

と入力すると次のように表示されます。

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   test2.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   test.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        test3.txt

上から順に「ステージングエリアにあるファイル(Changes to be committed)」、「ステージングエリアに追加されていない、変更されたファイル(Changes not staged for commit)」、「新たに追加されたファイル(Untracked files)」が表示されていることが分かります。

あとがき

次回は、gitでよく登場する「HEAD」という用語を解説します。

この記事について

この記事について、誤字や間違っている所がある場合は私のTwitterか、コメント欄から連絡をお願いします。

参考文献

Pro Git

Git,GitHubの使い方について、非常に詳しく丁寧に解説されています。
ですが、内容が初心者には難しいと思われるため一度入門記事等を読んで一通りGit,Githubを勉強してから読まれると理解が深まると思います。
pdf形式であれば、日本語版が無料で公開されています。 git-scm.com

次回の記事

terapotan.hatenablog.jp

前回の記事

terapotan.hatenablog.jp

連載記事一覧

terapotan.hatenablog.jp