Git

Git/GitHub

バージョン管理をGitで
学ぶチュートリアル

著者について

マイケル・ハートル(Michael Hartl)は、ウェブ開発の主要な入門書の一つである「Ruby on Railsチュートリアル」の作成者です。また、「Learn Enough」の共同創立者であり、主執筆者でもあります。以前は、カリフォルニア工科大学(Caltech)で物理学の講師をしており、そこで生涯功労賞(Lifetime Achievement Award for Excellence in Teaching)を受賞しています。ハーバード大学を卒業後、カリフォルニア工科大学で物理学博士号を取得。Y Combinator起業家プログラムの卒業生でもあります。

著作権とライセンス

Railsチュートリアル Copyright © 2020 by Michael Hartl(最終更新日: 2023/06/21 12:39:04 PT)

Railsチュートリアルで掲載しているすべてのソースコードは、MIT ライセンスおよびBeerware ライセンスの元で提供されています。なお、これらのライセンスはいずれか一方が有効になります。つまり、MITライセンスに基づいて使用する場合は、ビールも購入する必要はありません。

なお、「すべてのソースコード」とは、Railsチュートリアル内で題材としている「Railsアプリケーションのソースコード」を指します。「Railsチュートリアル」という教材は上記ライセンスで提供されていないのでご注意ください。営利・非営利問わず、事業で使用する場合は教材連携サービスをご利用ください。

The MIT License

Copyright (c) 2016 Michael Hartl

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
THE BEERWARE LICENSE (Revision 42)

Michael Hartl wrote this code. As long as you retain this
notice you can do whatever you want with this stuff.
If we meet some day, and you think this stuff is worth it,
you can buy me a beer in return.

第1章はじめてのGit

Git/GitHub編』は、ソフトウェア開発者や、開発者と共同作業する人にとって欠かせない3つのスキルを教えるために企画されたチュートリアルシリーズの最後を飾るコンテンツです。本編を学ぶために必要な条件は、先行する2つのチュートリアル『コマンドライン編』(Unixコマンドライン入門)と『テキストエディタ編』(テキストエディタ入門)を終了しておくことだけです。

本チュートリアルでは第3のスキル、すなわち「バージョン管理(version control)」を学びます。先行する2つのチュートリアルのときと同様、本編では学習者がアプリケーションにどんな種類があるかという知識を持ち合わせていないことを前提にしています。したがって、「バージョン管理とは何か」がまだわからない学習者も、本チュートリアルの対象に含まれます。既にバージョン管理を経験している方も、おそらく多くの学びを得られるはずです。いずれも、本チュートリアルを学ぶことで今後の学習の準備を整えつつ、驚くほど膨大な数のアプリケーションプログラムを手に入れられるようになります。さらに、巻末にはスペシャルボーナスも用意されていますのでどうぞお楽しみに(コラム 1.1)。

コラム 1.1. 本物のアーティストは作品を世に問う

Appleの伝説的な創業者のひとりであるSteve Jobsはかつてこんな言葉を残しています。「本物のアーティストは、作品を世に送り出すものだ」。Jobsの真意はこういうことです。誰にも内緒で自分の作品をひたすら磨き上げていたい(=恥をかきたくない)という誘惑は極めて大きい。だからこそ、ものづくりをする者は、その誘惑を断ち切って自分の作品を世に問わなければならない。すなわち作品を本当の意味で最後まで仕上げ、世の人々の眼前にさらすのだ。怖いか?そりゃ怖いだろう。作品を世に送り出せば、ファンだけではなく、必ずや無数の批判にもさらされるからだ。「自分の作品がみんなに嫌われたら次はどうしたらいいだろう?」という問いへの答えは「本物のアーティストになりたければ、批判にめげず自分の作品を世に問い続けろ」ということなのです。

ただし、作品を作る能力と、作品を売り込む能力は別物だと知っておくことも重要です。ものづくりをする人の多くは、ものを作ることには長けていても、それを売り込む方法を学ぼうとしないものです。ここでは皆さんがそういうことにならないよう、自分の作ったものを一般公開する方法を最初に学びます。本チュートリアルでは実際に、誰でもアクセスできるGitリポジトリ(repository)に自分の作ったものを2つ公開します。さらにボーナスとして、皆さんの友だちに堂々と自慢できるサプライズも用意してあります。

「バージョン管理」とは、言ってみればWordドキュメントやExcelスプレッドシートなどでありがちな「Report_2014_1.doc」や「Report_2014_2.doc」や「Report_2014_3.doc」、「budget-v7.xls」といった残念な履歴管理を解決する方法です。こういう思いつきで付けたとした思えないひどいファイル名が使われると、どのドキュメントがいつのバージョンなのか、どれが最新のファイルなのかを後で追いかけるときに筆舌に尽くしがたい苦痛を伴います。今どきはWordなどのアプリケーションにも多少バージョン管理機能が組み込まれていることはありますが、そうした機能はアプリケーションと強く結合してしまっているので、ドキュメントの種類が異なる場合には役に立ちません。そのため、多くのアプリケーション(Webサイトやプログラミングプロジェクトのほとんどを含む)では、特定のアプリケーションに依存しない「一般的な」バージョン管理ソリューションが欠かせなくなります。

いわゆる「バージョン管理システム(VCS)」とは、ソフトウェアプロジェクトで発生した変更点を自動的にトラッキングする(=追いかける)しくみを提供するためのものです。バージョン管理システムを導入することで、プロジェクトの作成者がファイルやディレクトリが直前のバージョンでどうなっていたかを簡単に調べられるようになり、バージョンを追いかける作業を軽減して本来進めたい高度な機能の開発に集中できるようになり、多くの作業者による共同作業もずっとやりやすくなります。さらに、バージョン管理システムは、作成したソフトウェアを本番のWebサイトやWebアプリケーションに手軽にデプロイ(=展開・配置)するのにも使えます。

そうしたわけで、バージョン管理システムを少なくとも1つスムーズに使いこなせるスキルは、例の「技術の成熟」(コラム 1.2)の中でも欠かすことのできない中核的な要素であり、開発者はもちろんデザイナーや管理職にとってもきわめて有用です。本チュートリアルで扱う「Git(ギット)」というバージョン管理システムは特に重要です。

コラム 1.2. 技術の成熟

本チュートリアルシリーズ全体を貫く主要なテーマのひとつが、「技術の成熟」を養うことです。つまり「ハードスキル」「ソフトスキル」の合わせ技によって、技術的な問題を魔法のように解決するスキル1です。『Git/GitHub編』はそうしたスキルを養ううえで重要な位置を占めています。

Gitを学ぶ場合の「技術の成熟」には、多くのスキルが含まれます。Gitコマンドの多くは、ターミナル画面にさまざまな情報を出力するので、その中のどれが重要でどれを無視していいかを見分けるためにも「技術の成熟」が必要です。Googleで上手に検索するスキルもそのひとつです。ネット上にはGitに関連した情報が大量にあるので、今の自分に必要なGitコマンドを正確に探し出すためのコツをつかむことが大切です。たとえば「リモートブランチを削除する」( 4.3.1)方法を知りたければ、「git delete remote branch」でググることでまともな情報を見つけられる可能性は高まるでしょう。

最後に、GitHubGitLabBitbucketのようなリポジトリホスティングサイトには、さまざまなセットアップ方法を支援するコマンドも用意されているので、皆さんが「技術の成熟」精神を発揮すれば、たとえこれから説明する内容の一部がよくわからないことがあったとしても、自信を持って操作手順を進められるようになります。

Gitを学ぶときに知っておくと便利なコマンドのひとつにgit helpがあります。これはGitの一般的なガイドラインを表示するためのものですが、特定のコマンドでgit helpを実行するとさらに詳しい情報を表示できます。たとえばgit help addを実行すればgit addについての詳しい情報が表示されます。git helpの出力は、『コマンドライン編』で学んだ「manページ」の表示と似ています。どちらも有用な情報が満載ですが、情報が今ひとつはっきりしないこともざらにあります。そんなときはいつものように「技術の成熟」精神を発揮して理解に努めましょう2

バージョン管理のしくみは、ここ十数年の間に大幅な進化を遂げています。Gitを筆頭とするバージョン管理ソフトウェアのファミリーには「RCS」「CVS」「Subversion」といったものも含まれますし、それぞれに「Perforce」「Bazzar」「Mercurial」といった多くの別実装もあります。様々なバージョン管理ソフトウェアの名前を例として並べましたが、これはバージョン管理ソフトウェアの種類があまりに多すぎて戸惑うほどだということを知っていただくのが目的なので、すべてを詳しく知っておく必要はありません。ただ、この中からバージョン管理システムをひとつ選ぶということは、文字どおり「commitする」ということであり3、多くの場合、後になってから別のバージョン管理システムに乗り換えるのは難しくなります。ありがたいことに、オープンソース界隈で長年繰り広げられてきたバージョン管理ソフトウェア戦争に、ここ数年圧倒的な覇者が出現しました。それが「Git」です。本チュートリアルのタイトルを「Version Control」にしなかった主な理由は、Gitがどこからどう見ても圧倒的な勝利を収めているからです。とはいうものの、本チュートリアルで学ぶバージョン管理の概念は十分一般性の高いものですし、何らかの理由で別のバージョン管理システムを使わなければならなくなったときにも、有用な前知識として活用できます。

Gitを最初に開発したのは、Linuxの生みの親として知られるLinus Torvalds(リーナス・トーバルズ)です4。GitはUnixの伝統の流れの中で設計されたコマンドライン形式のプログラムです(だからこそ、Gitを学ぶ前にUnixコマンドラインをしっかり学んでおくことが非常に重要なのです)。Gitは「強力」かつ「高速」という2つの素晴らしい特性を兼ね備えているので、オープンソースコミュニティで広く受け入れられました。しかしGitの技を学ぶのは簡単ではありません。なのに、世にある多くのGit入門書は延々と面倒な理論を紹介して終わってしまう傾向があります。バージョン管理の理論は、それはそれで興味深いものではありますが、理論を隅々まで理解しているのはごく一握りのGitユーザーだけなので心配は要りません5。ここで皆さんによいお知らせです。Gitを生産的に使いこなすのに必要なコマンドは大して多くありません。高度な話題や理論方面の関連資料については 4.7のリストにもある程度示しましたが、本チュートリアルでは皆さんが本当に必要なコマンドだけを集中的に解説する予定です。

Note: macOSをお使いの方は、今のうちに「コラム 1.3」の指示に従っておいてください。

コラム 1.3. macOSのシェルをBashに切り替える

macOSをお使いの方は、この時点で本チュートリアル向けに「正しい」シェルプログラムを使えるようにしておくべきです。macOS CatalinaからはデフォルトシェルがZ shell(Zsh)に変わってしまったのですが、本チュートリアルで行う操作の結果と一致させるにはBashと呼ばれるシェルに切り替えておく必要があります。

現在のシステムで実行されているシェルの種類を確認するには、以下のようにechoコマンドを用います。

  $ echo $SHELL
  /bin/bash

上を実行すると、$SHELLという環境変数の内容が出力されます。出力結果が上と同じであれば、既にBashが使われていますので、チュートリアルを終えるための特別な操作は必要ありません(ごくごくまれに$SHELL環境変数の内容が現在のシェルと一致しないことがありますが、その場合でも以下に紹介するシェル切り替えコマンドは問題なく使えます)。詳しくはLearn Enoughブログの『Using Z Shell on Macs with the Learn Enough Tutorials』記事をご覧ください。

echoの結果が上と異なる場合、以下のように出力される可能性があります。

  $ echo $SHELL
  /bin/zsh

この場合は以下のようにchsh(change shell)コマンドを実行します。

  $ chsh -s /bin/bash

コマンドを入力すると、ほぼ確実にシステムのパスワード入力を求められるでしょう。実際、このコマンドを実行するにはシステムのパスワードが必要なのです。終わったらCommand-Qキーを押してシェルプログラムをいったん終了し、シェルプログラムを再度起動しましょう。

シェルが切り替わったことを確認するには、以下のように再度echoコマンドを使います。

  $ echo $SHELL
  /bin/bash

おそらくこのとき、シェルの開始画面に以下のアラートが表示されますが、これは無視してください。

  The default interactive shell is now zsh.
  To update your account to use zsh, please run `chsh -s /bin/zsh`.
  For more details, please visit https://support.apple.com/kb/HT208050.

  [~]$

ここで紹介した切り替え手順はいつでも元に戻せますので、システムを壊すのではないかと心配する必要はありません。詳しくは『“Using Z Shell on Macs with the Learn Enough Tutorials』記事をご覧ください。

1.1 Gitのインストールとセットアップ

Gitを使うには、gitというコマンドラインプログラムからGitを利用するのが最も一般的です。このコマンドを実行すると、通常のUnixディレクトリが「リポジトリ6」というものに変わり、プロジェクトの変更をトラッキング(=追いかける)できるようになります7。本節では最初にGitのインストール方法(まだインストールされていない場合)と、最初だけ行っておくいくつかの設定について説明します。

ここから先に進む前に、まずは現在のシステムにGitがインストール済みかどうかを確認しておく必要があります。繰り返しますが、私たちは「Unixの伝統」の上で作業していますので、本チュートリアルで使うコンピュータ環境としてmacOSまたはLinuxを使う(=つまりWindows環境を使わない)ことを強くおすすめします。Linux環境は、おそらく仮想マシン上で実行することになるでしょう(コラム 1.4)。

コラム 1.4. Unixを使う

先行する2つのチュートリアルと同様、本チュートリアルも皆さんのコンピュータ環境で何らかの「Unix的環境」にアクセス可能であることを前提としています。既にmacOSやLinuxをお使いであれば何の問題もありませんが、Windowsをお使いの方はクラウドIDEを使うか、頑張ってLinux仮想マシンをインストールしてください。どちらも『Rails Girls インストール・レシピ』や『Learn Enough Dev Environment to Be Dangerous』で扱っています。

なお、WindowsのDOSプロンプトやPower Shellは、Unixとはまったく異なる環境なので、GitやRubyを満足に動かすにはかなりの努力が必要になります。現時点では『Rails Girls インストール・レシピ』に沿うことをおすすめします。

Gitが使える状態かどうかを調べる最も簡単な方法は次のとおりです。ターミナルウィンドウを起動して、コマンドラインで以下のようにwhichコマンドを実行し8git実行可能ファイルへのパスが表示されるかどうかを確認します。

$ which git
/usr/local/bin/git

結果に何も出力されないか「command not found」などと表示される場合は、Gitを自分でインストールしなければならないということになります。Gitを手動インストールするには、公式のGitドキュメントにある「1.5 使い始める - Gitのインストール 」の手順に従います。これは「技術の成熟」精神を発揮する良い機会となるでしょう(1.2)。

Gitをインストールしたら、プロジェクトを開始する前に、もうひと手間かけていくつかセットアップを終えておく必要があります(リスト 1.1)。このリストには「グローバルな」セットアップが記載されています。つまりこれらの設定は、1台のコンピュータにつき1度は(かつ1度だけ)行わなければならないということです。なお、今はコマンドの細かな意味がわからなくても心配ありません。

リスト 1.1: 1度だけ行うグローバル設定
$ git config --global user.name "自分の姓名(ローマ字)"
$ git config --global user.email <自分のメールアドレス(your.email@example.comなど)>

Gitでこのグローバル設定を行うことで、今後自分が行うプロジェクトの変更を、自分の「名前」や「メールアドレス」で調べられるようになります。この設定は、Gitで共同作業を行う場合に特に役立ちます(4)。なお、リスト 1.1で設定した名前やパスワードは、今後皆さんが自分のプロジェクトを一般公開するときに誰でも見えるようになるので、公にしたくない個人情報をここに書き込まないようご注意ください。

本チュートリアルでは、上の必須設定の他に、いくつかの高度なセットアップオプションについてもこの後扱います( 4.6)。必須ではありませんが、これらの設定についても早めに終えておくことをおすすめします。Gitを少し触ったことのある方や、Unixコマンドラインに十分詳しい方は、今のうちに「 4.6」の設定を終えておくことをおすすめしますが、そうでない方は何もせずこのまま進みましょう。

1.1.1 演習問題

  1. コマンドラインでgit helpを実行し、コマンドリストの最初に何が書かれているかを調べましょう。
  2. git helpで出力されるヘルプテキストの量が多すぎると、ターミナルをスクロールしないとすべて表示しきれないかもしれません。そんなときにgit helpの出力結果をインタラクティブに前に進めたり後ろに戻ったりするのに使えるコマンドは何でしょうか?(なおシステムによってはマウスでスクロールできることもありますが、マウスが使えない環境も多いので、マウスに頼るのは安直です。)ヒント: 出力をパイプlessコマンドにつなぎます。
  3. Gitのグローバル設定は、ホームディレクトリ直下の隠しテキストファイルに保存されます。自分の好きなツール(catでもlessでもテキストエディタでも何でも構いません)を用いて、~/.gitconfigというファイルの中身を調べてみましょう。そして、リスト 1.1の設定に対応する内容が、このファイルの中でシンプルなテキスト形式として保存されていることを確かめましょう。

1.2 リポジトリを初期化する

今度は、いよいよプロジェクトを1つ作成してGitの管理下に置いてみましょう。頭の中にはっきりと思い浮かべられる「Gitの具体的な応用例」があると、Gitのしくみや、Gitがあると何が嬉しいのかを十分理解するのに大いに役立ちます。そこで、シンプルなプロジェクトを1つ作成し、「Homeページ」「Aboutページ」という2つのWebページを含むささやかなWebサイトをそこに構築して、その変更履歴をGitで追うことにします9。まずはreposというリポジトリ用ディレクトリの下に、websiteという一般的な名前のディレクトリを1つ作成します。

[~]$ mkdir -p repos/website

ここでは、『コマンドライン編』で解説したmkdir(make directory)コマンドに、-pオプションを追加しています。mkdirにこのオプションを指定すると、中間ディレクトリ(ここではrepos)も同時に作成できます。また、リスト 4.15の設定により、プロンプトにはカレントディレクトリ(=現在のディレクトリ[~])が表示されるようになっていることにもご注目ください。

ディレクトリを作成したら、以下のようにcd(change directory)コマンドでそのディレクトリに移動します。ディレクトリを移動するときに、Tabキーを押してディレクトリ名を補完できることを思い出しましょう。私なら「cd re⇥w⇥」と入力するでしょう。

[~]$ cd repos/website/
[website]$

websiteディレクトリには何もファイルがありませんが、その状態でもこのディレクトリを「リポジトリ」に変換できます。見方を変えれば、Unixディレクトリにあるすべてのファイルやサブディレクトリの変更履歴を追えるよう、そのディレクトリを拡張したと考えてもよいわけです。さて、リポジトリを新規作成するには、init(initialize: 初期化の略)コマンドを使います。これを実行すると、そのディレクトリに.gitという特殊な隠しディレクトリが作成され、Gitはここにプロジェクトの変更履歴を追うのに必要な情報を保存します(通常のディレクトリとGitリポジトリの違いは、正しく設定された.gitディレクトリがそこに存在するかどうかという違いだけです)。

Gitのコマンドは、常に「git」の後ろにサブコマンド名を付ける形で実行します。つまりリポジトリを初期化するコマンドは「git init」となります(リスト 1.2)。

リスト 1.2: Gitリポジトリを初期化する
[website]$ git init
Initialized empty Git repository in /Users/mhartl/repos/website/.git/
[website (master)]$

ところで、リスト 1.2のプロンプト表示に「[website]」という文字が表示されているのは、『テキストエディタ編』で学んだBashのカスタマイズに「 4.6.2」の高度なセットアップを加えたことによるものなので、皆さんの環境ではこれと異なる表示になる可能性があります10。特に、リスト 1.2にはGitの「デフォルトブランチ」として「master」という名前が表示されています11。ブランチとは何かがよくわからなくても今は問題ありません。ブランチについて詳しくは「 3.3」で解説します。

1.2.1 演習問題

  1. ls -a」コマンド(『コマンドライン編』で解説)を実行して、websiteディレクトリ内にあるファイルやディレクトリをすべて表示(list all)してみましょう。Gitリポジトリで使う隠しディレクトリはどんな名前でそこに表示されていますか?(Gitの隠しディレクトリは、プロジェクトごとに1つ存在します。)
  2. 上の演習問題の結果を用いて、Gitの隠しディレクトリそのものに対してlsコマンドを実行しましょう。次にGitのメインの設定ファイルがその中のどれかを推測し、推測したファイルに対してcatコマンドを実行して中身を表示してみましょう。

1.3 初めての「コミット」

リポジトリに何もファイルがない状態では、Gitの初期化は完了できないようになっています。そこで、カレントディレクトリに何か変更を加える必要があります。さしあたって今はtouchコマンド12を用いて空のファイルを1つ作成することにします。ここではシンプルなWebサイトを作りたいので、Webサイト構築でほぼ一般的に使われる命名慣習に基づいて、メインページをindex.htmlと呼ぶことにします。

[website (master)]$ touch index.html

最初のファイルを作成したので、git statusコマンドを実行して結果を見てみましょう。

[website (master)]$ git status
On branch master

No commits yet

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

  index.html

nothing added to commit but untracked files present (use "git add" to track)

index.htmlファイルのステータスは「untracked」となっています。これは、Gitがindex.htmlファイルをまだ認識していないことを表します。そこで、git addを実行してこのファイルをGitに追加します。

[website (master)]$ git add -A

ここで使った-Aオプションは、「untracked状態のファイルをすべてGitに追加せよ」とGitに指示しています。ここではuntracked状態のファイルは1つしかありませんでしたが、複数あった場合はそのすべてが追加されるという意味です。なお、untracked状態のファイルを個別にGitに追加する方法については演習問題に回します( 1.3.1)。ちなみに、Stack OverflowというQ&Aサイトでは、これとほぼ同等のコマンドである「git add .」が紹介されています。このドット「.」はカレントディレクトリを表すときにもよく使われます13

git add -Aの実行結果を見るには、git statusを再度実行します。

[website (master)]$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

  new file:   index.html

「to unstage」という言葉が示すとおり、index.htmlファイルのステータスは「untracked」から「staged」に変更されています。「staged」というステータスは、そのファイルをGitリポジトリに追加可能になったことを表します(まだ追加はされていません)。「untracked」「unstaged」「staged」というステータスは、Gitでよく使われる4つのステータスの中の3つです(図 1.1)。技術的には「untracked」と「unstaged」は違うステータスなのですが、git addコマンドを実行すれば「untracked -> tracked」と「unstaged -> staged」を同時に行うので、実際にはこの違いはほとんど重要ではありません。

images/figures/git_status_sequence
図 1.1: Gitで主に使われるファイル変更時のステータス遷移

図 1.1に示したように、変更を「staging」エリアに移動すると、その変更をgit commitコマンドで「コミット(commit)」してローカルGitリポジトリの一部に登録できる状態になります。後ほど、git pushコマンドで図 1.1の最後の状態に進む方法についても説明します( 2.3)。git commitコマンドを実行するときは、ほとんどの場合-mオプションで「コミットメッセージ」も追加します。コミットメッセージには、そのコミットを行う理由を端的に記述します(コラム 1.5)。ここでは新しいリポジトリを初期化することが目的なので、以下のように「Initialize repository」と書くことにします。

[website (master)]$ git commit -m "Initialize repository"
[master (root-commit) 879392a] Initialize repository
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.html

上記の出力結果は、著者のものです。細かな数値などが異なっていても問題ありません。

コラム 1.5. Gitに「コミットする」とは

Gitでは、変更をコミットするときに必ず「コミットメッセージ」を追加しなければならないよう設計されています。コミットメッセージには、そのコミットの目的を1行以内、最大72文字程度に収めるのが普通ですが、必要であれば詳細をその下の行に続けて書くこともできます( 4.2.3)。英語でのコミットメッセージの書き方について一概には言えません14が、本チュートリアルでは英語の「現在形」かつ「命令形」をコミットメッセージのスタイルとして採用しています15

英語では命令形で書いても、それだけでは日本人が考えるような無礼なニュアンスにはなりません。日本語と違い、動詞の選びなど別の要素の方が丁寧さに影響するのです。そもそもここで命令される相手は人間ではなくGitなので、命令形で書いただけでは失礼にはあたりません。

社内プロジェクトなどではコミットメッセージを日本語で書くこともよくあります。基本的にはそのプロジェクトでの指示に従うことになりますが、特に指示がない限り日本語の「終止形」(「〜を確認する」など)が使われることがほとんどです。「体言止め」も利用可能ですが、たとえば「〜を確認」とすると、「確認済み」なのか「確認せよ」なのか「確認したい」なのか、内容があいまいになりやすいので、コミットメッセージに限らず体言止めを使うときは注意しましょう。

オープンソースのソフトウェアではコミットメッセージを英語で書くことがほとんどなので、英語のコミットメッセージを書く機会があったら、特別な指示がない限り英語の「命令形」で書くことをおすすめします。詳しくはGitHubの『Shiny new commit styles』記事をご覧ください。

このあたりで、git logコマンドを実行してコミット履歴を見てみましょう。

[website (master)]$ git log
commit 879392a6bd8dd505f21876869de99d73f40299cc
Author: Michael Hartl <michael@michaelhartl.com>
Date:   Thu Dec 17 20:00:34 2015 -0800

    Initialize repository

Gitのコミットは、「ハッシュ」と呼ばれる文字列によって区別されます。ハッシュとは、文字や数字の並んだ一意の文字列のことで、Gitはこのハッシュを用いてコミットをラベリングし、コミットの変更内容を取り出すときにもハッシュを指定します。上の表示例の場合、以下の文字列がハッシュです。

879392a6bd8dd505f21876869de99d73f40299cc

ハッシュの文字列はコミットごとに必ず大きく異なるようになっています16。このハッシュ文字列の生成には「SHA」(発音は「シャー」)というアルゴリズムが用いられますが、これはSecure Hash Algorithmの略です。「 3.4」ではこのSHAを高度なGit操作に応用する方法についても学びます。

1.3.1 演習問題

  1. 上で作った自分のリポジトリディレクトリで、touchコマンドを使ってfooという空ファイルとbarという空ファイルをそれぞれ作成してみましょう。
  2. git add fooコマンドを実行してfooというファイルを「staging」エリアに追加し、git statusで結果を確認しましょう。
  3. git commit -mコマンドに続けて適切なコミットメッセージを入力し、fooファイルをリポジトリに追加しましょう。(コミットメッセージは引用符で囲む必要があります。)
  4. git add barコマンドを実行してbarというファイルを「staging」エリアに追加し、git statusで結果を確認しましょう。
  5. 今度は「-m」オプションを付けないでgit commitコミットを実行してみましょう。Vimの知識を応用して、「Add bar」というコミットメッセージを追加したら、保存してVimを終了してみましょう。
  6. git logコマンドを実行して、ここまでの演習で行ったコミットが正しく行われたことを確認しましょう。

1.4 diffを表示する

変更内容を実際にコミットする前に、変更内容を表示して確認できれば何かと便利です。この方法を学ぶために、index.htmlファイルにechoコマンドの出力をリダイレクトして「hello, world」ページを作ります。

[website (master)]$ echo "hello, world" > index.html

コマンドライン編』で学んだUnixのdiffユーティリティを思い出しましょう。たとえばfoobarの中身を比較して差分を表示するには以下のように入力します。

$ diff foo bar

Gitにもこれに似たgit diffという機能があります。デフォルトでは、現在のプロジェクトの「直前のコミット」と「unstagedな変更」の差分を表示します。

[website (master)]$ git diff
diff --git a/index.html b/index.html
index e69de29..4b5fa63 100644
--- a/index.html
+++ b/index.html
@@ -0,0 +1 @@
+hello, world

 1.3で追加したファイルの中身は空だったので、差分には以下の追加だけが表示されます。

+hello, world

git commitコマンドに「-a」オプション(allの略)を追加して、この変更をローカルGitリポジトリにコミットできます。現在存在するファイルに対して行われた変更点は、すべてコミットされます(リスト 1.3)。

リスト 1.3: 変更されたすべてのファイルの変更内容をコミットする
[website (master)]$ git commit -a -m "Add content to index.html"
[master 03aff34] Add content to index.html
 1 file changed, 1 insertion(+)

なお「-a」オプションの対象になる変更内容は、「既にリポジトリに追加されたファイル」の変更点だけです。つまり何か新しいファイルを作成したら、git add -Aを実行してファイルをローカルリポジトリに追加しておくことが重要です( 1.3)。新しいファイルをリポジトリに追加し忘れたままgit commit -aを実行してGitに怒られるというのは実にありがちです。この問題については、演習問題で実際に対処しながら学べます( 1.4.1)。

変更を追加してコミットしたので、差分は表示されません。

[website (master)]$ git diff
[website (master)]$

git diffで差分を確認するのに必要なのは、単に変更を追加することだけです。しかし、git add -Aを実行し「staged」状態となったファイルの差分はgit diffでは表示されません。「staged」の変更と、リポジトリの直前のバージョンとの違いはgit diff --stagedで確認できます。

ここまでの変更履歴を見るにはgit logを実行します。

[website (master)]$ git log
commit 03aff34ec4f9690228e057a4252bcca169a868b4
Author: Michael Hartl <michael@michaelhartl.com>
Date:   Thu Dec 17 20:03:33 2015 -0800

    Add content to index.html

commit 879392a6bd8dd505f21876869de99d73f40299cc
Author: Michael Hartl <michael@michaelhartl.com>
Date:   Thu Dec 17 20:00:34 2015 -0800

    Initialize repository

1.4.1 演習問題

  1. touchコマンドでbazという空のファイルを作成し、git commit -am "Add baz"を実行するとどうなるかを観察しましょう。
  2. bazファイルをgit add -Aコマンドで「staging」エリアに追加し、続いて「"Add bazz"」というコミットメッセージを添えてコミットしてみましょう。
  3. 上のコミットメッセージには入力ミスがあります。git commit --amendコマンドで「bazz」を「baz」に修正してみましょう。
  4. git logコマンドを実行して、直近のコミットのSHAハッシュを表示しましょう。続いてgit show <SHA>にそのSHAハッシュを当てはめて、メッセージのミスが正しく修正されたことを確認しましょう。

1.5 HTMLタグを追加する

これで、Git作業のワークフローで使われる最もシンプルで主要な要素はすべてご紹介できました。この節と次の節では、これまでやってきた作業を復習しながら、さらに詳しく確認することにします。ここでは小さなコミットを頻繁に行いながら変更作業を練習しますが、実際の業務でこのように作業すべきということではありません(コラム 1.6)。それでもこの作業はGitの基礎として非常にふさわしいものですし、皆さんが自分に合うワークフローや開発手順を作り上げていくうえでも確かな基盤となるでしょう。

コラム 1.6. コミットでよくある問題

Gitで学ぶときにありがちなのが、「いつどういうタイミングでコミットするか」を理解することです。残念ながらこれについては一言で答えるわけにいきません。コミットを行うタイミングは、現実には人やプロジェクトによってかなり違います17せめてアドバイスするとしたら「作業を自然に区切れるタイミングになった」、あるいは「変更作業が今失われたら困るぐらいの変更量になった」ときがコミットする目安です。実際のGit作業では、そのときそのときでコミットの頻度や量が変わりますし、たとえば「変更量がかなり大きくなってからいったんコミットし、続いて重要度の低い細かな変更をひとつコミットする」などという進め方も普通に行われます。コミットのサイズがものすごく大きくなったり小さくなったりするのは少々困りものではありますが、かといってそれを避けてコミットサイズを毎回同じぐらいにするのも難しいことです。

多くの開発チームでは(オープンソースプロジェクトのほとんどもそうですが)、コミットサイズの大きさや頻度、読みやすさのためコミットを「スカッシュ(squash)」して複数コミットを1つに固めるタイミングなどについて独自の目安を定めています18。コミットのタイミングなどについては、そのプロジェクトで決められている目安に従うことをおすすめします。

実際に仕事でGitを使うと、ときにいろんな人から「コミットの変更量が多すぎて読むのがつらい」「コミットが細かく分かれすぎていて追いかけにくい」という互いに正反対の苦情をもらうこともあると思います。「コミット量は大きければいい」のでもなければ「コミット量は小さければいい」のでもなく、「相手にとって読みやすいコミット」とは何なのかを日頃から考えるようにしましょう。

そして、何より大事なのは「あんまりくよくよしない」ことです。コミットのタイミングについては経験を積んでいくことで確実に上達できます。

これまでと同様に、今回もメインのindex.htmlファイルで作業することにします。まず、このファイルをテキストエディタとブラウザの両方で開いてください。VSCodeエディタでファイルを開くにはcodeコマンドを使用します。ちなみにmacOSの場合は、openコマンドでブラウザにファイルを開くことができます。Macを使っていない方は、GUIのファイルブラウザでファイルをダブルクリックすればデフォルトのブラウザでファイルが開きます(図 1.2)。

[website (master)]$ code index.html
[website (master)]$ open index.html   # macOSのみ。それ以外の場合は、GUIを使用します。

ファイルを開くと、図 1.3図 1.4のように表示されるでしょう。

images/figures/index_filesystem_browser
図 1.2: index.htmlをファイルシステムのブラウザで表示したところ
images/figures/hello_world_vscode
図 1.3: 最初のHTMLファイルをVSCodeで開いたところ
images/figures/hello_world_safari
図 1.4: 最初のHTMLファイルをブラウザで開いたところ

これでファイルを変更する準備が整いました。元の「hello, world」というテキストを「h1見出し」に変更します。Webの言語であるHTMLでは、これをHTML「タグ」を使って行います(ここではh1タグを使います)。ほとんどのブラウザではh1を指定すると文字のフォントサイズが大きくなるので、h1タグに変更するとhello, worldという文字列が大きくなるはずです。これを行うには、今開いているindex.htmlファイルの中身をリスト 1.4に置き換えます19

リスト 1.4: トップレベル見出し
<h1>hello, world</h1>

リスト 1.4には、ほとんどのHTMLタグで用いられる基本的な構造が示されています。まず<h1>のような「開始タグ」は、タグ名(ここではh1)を<>で囲んだものです。そしてテキストの後ろには「閉じタグ」があります。形は開始タグと似ていますが、</h1>のようにスラッシュが追加されている点だけが異なります。なお、WebのURIアドレスと同様、「バックスラッシュ」ではなく「スラッシュ」を使う点にご注意ください20

Webブラウザの画面を更新すると、indexページが図 1.5のように表示されるはずです。先ほどお約束したように、トップレベルにあるテキストのフォントサイズがちゃんと大きく、しかも太字になりました。

images/figures/hello_world_h1
図 1.5: h1タグを追加した結果

さて、いつものようにgit statusgit diffを実行して、Gitにこれから何がコミットされるのかを学ぶことにしましょう。慣れてくれば、これらのコマンドを必要に応じて実行できるようになるでしょう。以下のステータスには、index.htmlに変更が発生していることが示されています。

[website (master)]$ git status
On branch master
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:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

git diffの差分には、削除された1行が-記号で示され、追加された1行が+記号で示されています。

[website (master)]$ git diff
diff --git a/index.html b/index.html
index 4b5fa63..45d754a 100644
--- a/index.html
+++ b/index.html
@@ -1 +1 @@
-hello, world
+<h1>hello, world</h1>

Unixのdiffユーティリティと同様に、コードやmarkupで変更された箇所が隣り合って表示されているので、どこがどう変更されたかがひと目でわかります21

さて、これで変更点をコミットする準備が整いました。リスト 1.3では-aオプションと-mオプションを別々に指定して、変更点をすべてコミットしつつコミットメッセージを追加していますが、実際には-amのようにひとつにまとめることもできます(リスト 1.5)。

リスト 1.5: -amオプションを指定してコミットする
[website (master)]$ git commit -am "Add an h1 tag"

1.5.1 演習問題

  1. git logコマンドを実行するとコミットメッセージだけが表示されます。これはこれで邪魔にならなくてよいのですが、他にも情報を表示したいこともあります。そこでgit log -pのように-pオプションを追加して実行し、コミットごとに差分を表示できることを確かめてみましょう。
  2. リスト 1.4h1タグの下にp(パラグラフ)タグを追加して、その中に「Call me Ishmael.」と書いてみましょう。変更結果は図 1.6のようになるはずです。(ここでうまくいかなくても大丈夫です。この演習の答えは 1.6リスト 1.6で取り込まれます。)
images/figures/ishmael_paragraph
図 1.6: 短いパラグラフを1つ追加した結果

1.6 HTML構造を追加する

h1タグはめでたくWebブラウザに表示されましたが(図 1.5)、h1タグやpタグだけでは「正しいフォーマットの」Webページとは言えません。まず、各ページにはhtmlタグを置き、その中にheadタグbodyタグを置き、さらにドキュメントタイプを指定する「doctype」が必要です。特にドキュメントタイプは、「HTML5」のようなHTMLバージョンを指定するときに使われます。なお、今の段階でこれらの意味がわからなくても心配ありません。詳しくは次のチュートリアル『HTML編』で説明します。

上で述べた注意点をindex.htmlに反映すると、完全なHTML構造ができあがります(リスト 1.6)。ここにはリスト 1.4h1タグも、図 1.6pタグも揃っています。なお、headタグの内側にあるtitleタグが空になっていますが、一般にはWebページには必ずタイトルを付けるべきです。index.htmlへのタイトルの追加は演習問題に回します( 1.6.1)。

リスト 1.6: 構造を追加したHTMLページ
 1 <!DOCTYPE html>
 2 <html>
 3   <head>
 4     <title></title>
 5   </head>
 6   <body>
 7     <h1>hello, world</h1>
 8     <p>Call me Ishmael.</p>
 9   </body>
10 </html>

先ほどのコード(リスト 1.4)よりもだいぶ中身が増えてきたので、1行ずつ分解して確認してみましょう。

  1. ドキュメントタイプ宣言
  2. html開始タグ
  3. head開始タグ
  4. title開始タグと閉じタグ
  5. head閉じタグ
  6. body開始タグ
  7. トップレベル見出し(h1)
  8. 演習( 1.5.1)で使ったパラグラフ
  9. body閉じタグ
  10. html閉じタグ

いつものようにgit diffを実行すれば変更内容を確認できます(リスト 1.7)。

リスト 1.7: HTML構造を追加したときの差分
[website (master)]$ git diff
diff --git a/index.html b/index.html
index 4b5fa63..afcd202 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,10 @@
-<h1>hello, world</h1>
+<!DOCTYPE html>
+<html>
+  <head>
+    <title></title>
+  </head>
+  <body>
+    <h1>hello, world</h1>
+    <p>Call me Ishmael.</p>
+  </body>
+</html>

リスト 1.7には何行もの差分が表示されていますが、Webブラウザの表示を更新してもほとんど違いが現れていません(図 1.7)。変更前の図 1.6との違いは、せいぜいトップレベル見出しの上の空きスペースの高さがほんの少し変わったぐらいです。変更後のHTML構造は大きく改善されましたが、これは主にページをHTML5標準に準拠させるためだけのものでしかありません22

images/figures/html_structure
図 1.7: HTML構造を追加しても見た目はほとんど変わらない

他に新しく追加したファイルはないので、git commit -amを実行すればすべての変更点がコミットされます(リスト 1.8)。

リスト 1.8: HTML構造の追加をコミットするコマンド
[website (master)]$ git commit -am "Add some HTML structure"

1.6.1 演習問題

  1. index.htmlファイルに「A whale of a greeting」というタイトルを追加し、ブラウザ表示のどこが変わるかを見てみましょう。なおGoogle Chromeでの表示結果を図 1.8に示します。
  2. 新しいタイトルを追加するコミットを実行してみましょう。コミットメッセージは自分で考えたものを使ってください。コミット内容が期待どおりであるかどうかをgit log -pコマンドで確認しましょう。
  3. リスト 1.6の内容をW3CのHTMLバリデーターに貼り付けて、Webページがまだ有効ではない(つまりエラーが表示される)ことを確認してみましょう。
  4. 上のバリデーターを使って、タイトルを入力した現在のindex.htmlが有効になっている(つまりエラーが表示されない)ことを確認しましょう。なお、warning(警告)は無視して構いません。
images/figures/page_title
図 1.8: ブラウザにページのタイトルが表示されたところ

1.7 まとめ

本節で扱った重要なコマンドを表 1.1にまとめます。ここには演習問題で扱った内容も含まれます。

コマンド 説明
git help コマンドのヘルプを表示する $ git help push
git config Gitを設定する $ git config --global …
source <file> シェル設定ファイルの変更を有効にする $ source ~/.bash_profile
mkdir -p 必要なら中間ディレクトリも作成する $ mkdir -p repos/website
git status リポジトリのステータスを表示する $ git status
touch <name> 空のファイルを作成する $ touch foo
git add -A すべてのファイルやディレクトリをstagingエリアに追加する $ git add -A
git add <name> 指定のファイルやディレクトリをstagingエリアに追加する $ git add foo
git commit -m 「staged」な変更にコミットメッセージを添えてコミットする $ git commit -m "Add thing"
git commit -am 変更内容をstagingエリアに追加し、コミットメッセージを添えてコミットする $ git commit -am "Add thing"
git diff コミット同士やブランチ同士などの差分を表示する $ git diff
git commit --amend 直前のコミットを修正する $ git commit --amend
git show <SHA> コミットのSHAハッシュを指定して差分を表示する $ git show fb738e…
表 1.1: 1の重要なコマンド
2. こうしたhelpコマンドやmanページは多くの場合、「それがどのようなものなのか」という情報は詳しく書かれていますが、「それをどんなときにどう使うか」という情報については記述が薄いことがよくあります。
3. commit(=引き返せない形で関わる、という意味でもある)と書いたのはダジャレです。本チュートリアルを終える頃にはわかると思いますので、今は意味不明でも心配無用です。
4. なお、Gitという言葉は英国のスラングで「間抜け」「嫌なやつ」を暗に指す品の悪い言葉なのですが、Linusはこの種のジョークを好んで、LinuxやGitという名前を自分自身になぞらえて命名したのです。
5. Webコミックxkcdの「Git」でも示されているように。
6. repository: 略してrepとも呼ばれます。
7. この後「 1.2」でも説明しますが、Gitでは「.git」という特殊な隠しディレクトリに変更履歴を保存します。なおこれは、本チュートリアルの今の段階では重要ではありません。
8. このwhichについては『コマンドライン編』でも解説しています
9.HTML編』や『CSS & Design編』では、この基礎知識を用いてさらに複雑なサイトを構築します。
10. Zshでこれと同じカスタムプロンプトを設定する方法が知りたい方は、Learn Enoughブログの『Using Z Shell on Macs with the Learn Enough Tutorials』記事をご覧ください。
11. このmasterというデフォルトブランチ名は、git initを実行すると自動的に作成されますが、別の名前をデフォルトブランチ名にすることを好む開発者も増えています。デフォルトのmasterブランチを別の名前に変える方法について詳しくは拙記事『Git-flowのデフォルトブランチをmasterからmainに変える方法』をご覧ください。なお、今後作られるプロジェクトではmainが使われることが増えると予想されます。
12. touchコマンドは、『コマンドライン編』で解説しています。
13. ごくまれに「git add -A」と「git add .」の挙動が同じにならないことがあります。Gitの公式ドキュメントに記載されているのは前者なので、本チュートリアルでは前者を用いることにしています。
14. xkcdの『Git Commit』でもネタにされています。
15. 重要なのは英語の「過去形」を使わないことです。Gitではコミットリストを「一連のテキストの移り変わり」としてモデル化していますが、このモデルでは「〜をした」という歴史を記述する過去形ではなく、「〜せよ」という命令形でコミットメッセージを記述する方が自然です。
16. ハッシュ文字列は、ファイルの変更内容に応じて生成されます。ファイルの内容を1文字でも変更するとハッシュ文字列はがらりと変わります。
17. xkcdの「Git Commit」でネタにされているように。
18. スカッシュとは何かについては、例の「コラム 1.2」精神を発揮してググってみましょう
19. テキスト編集の例で全般に言えることですが、リストのコードをコピペするよりも、自分でコードを手入力する方がずっと多くのことを学べます。
20. スラッシュとバックスラッシュがよく取り違えられるというネタはxkcdの「Trade expert」でも取り上げられています。
21. 特にコード以外の普通の文章の差分を確認するとき、--color-wordsオプションを使うのがとても便利です。通常のdiffユーティリティだと違いがわかりにくいと思ったら、git diff --color-wordsで差分を色分け表示することをおすすめします(このオプションは通常のUnix diffプログラムでも使えます)。
22. 先ほども述べたとおり、本当はページタイトルが空なので正確には標準を満たしているとは言い切れません。タイトルの追加は演習問題に回します(1.6.1)。
前の章
第1章 はじめてのGit Git / GitHub編
次の章