学習20日目:JSPとサーブレットを一通り終えた。

今日の学習時間。

  • Day:20
  • Today:11h
  • Total:122h

学習内容について。

使用頻度の高いJSTLタグ。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>JSTLのテスト</title>
    </head>
    <body>
        <c:set var="a" value="2" />
        <c:set var="b" value="3" />
        <c:set var="c" value="${a + b}" />
        <p>c = <c:out value="${c}" /></p>

        <c:set var="d" value="80" />
        <c:if test="${d >= 60}">
            <p>合格です!</p>
        </c:if>

        <c:set var="e" value="40" />
        <c:choose>
            <c:when test="${e >= 60}">
                <p>合格です!</p>
            </c:when>
            <c:otherwise>
                <p>赤点です…補講を行います</p>
            </c:otherwise>
        </c:choose>

        <c:forEach var="i" begin="0" end="9" step="1">
            <p><c:out value="${i}" /></p>
        </c:forEach>

        <c:set var="nums" value="10,20,30,40,50" />
        <c:forEach var="num" items="${nums}">
            <p><c:out value="${num}" /></p>
        </c:forEach>
    </body>
</html>

上記コードはスクリプトレットやスクリプト式で記述したtest2.jspとの比較。

まずは変数の表示。
<c:set var="a" value="2" />
<c:set var="b" value="3" />
<c:set var="c" value="${a + b}" />
<p>c = <c:out value="${c}" /></p>
  • <c:set>で、そのJSP内で利用する変数を定義
  • varに変数名、valueに変数の中に代入したい値を指定
  • <c:out>cの中身を表示する指定を記述
  • 変数の中身を表示する指定の書き方に使うのがEL式
条件分岐。
<c:set var="d" value="80" />
<c:if test="${d >= 60}">
    <p>合格です!</p>
</c:if>
ifのみの場合
  • <c:if>タグを使用
  • 条件式はtestのところにEL式を使って指定
  • 条件に満たない場合は何も表示されない
<c:set var="e" value="40" />
<c:choose>
    <c:when test="${e >= 60}">
        <p>合格です!</p>
    </c:when>
    <c:otherwise>
        <p>赤点です…補講を行います</p>
    </c:otherwise>
</c:choose>
elseがある場合
  • <c:choose><c:when><c:otherwise>を使用
  • <c:choose>タグの中で条件分岐を行う
  • <c:when>タグは複数記述可能(下記コード例)=else if
  • <c:otherwise>タグの中にすべての条件式を満たさなかった場合の処理を記述
<c:set var="e" value="40" />
<c:choose>
    <c:when test="${e >= 80}">
        <p>よくできました!!</p>
    </c:when>
    <c:when test="${e >= 60}">
        <p>合格です!</p>
    </c:when>
    <c:otherwise>
        <p>赤点です…補講を行います</p>
    </c:otherwise>
</c:choose>
繰り返し。
<c:forEach var="i" begin="0" end="9" step="1">
    <p><c:out value="${i}" /></p>
</c:forEach>
通常のfor文のような繰り返し
  • カウンタを利用した繰り返し
  • カウンタの変数はvarで指定
  • 初期値はbeginに指定
  • 終わりの値はendに指定
  • 増分はstepに指定
  • <c:out>を使って表示
<c:set var="nums" value="10,20,30,40,50" />
<c:forEach var="num" items="${nums}">
    <p><c:out value="${num}" /></p>
</c:forEach>
iteratorのような繰り返し
  • リストから1件ずつ取り出して処理
  • <c:forEach>を使用
  • 最初に<c:set>numsというリストを作成
  • itemsにリストや配列を指定

HTMLをテンプレート化する方法。

  • サイト内で共通したデザインの部分はテンプレートとして用意
  • 各JSPファイルからテンプレートを取り込めばヘッダーとフッターを記述しているファイルは1つだけで済む
  • JSTLの<c:import><c:param>のタグを利用して取り込む
  • 下記コード例
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<% request.setCharacterEncoding("UTF-8"); %>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title><c:out value="${param.title}" /> | サンプルサイト</title>
    </head>
    <body>
        <header>
            <h1><c:out value="${param.title}" /></h1>
        </header>

        <div id="main">
            ${param.content}
        </div>

        <footer>
            (c) Kiki Keiten
        </footer>
    </body>
</html>
  • import_a.jspの内部で<c:import>を使ってapp.jspのテンプレートファイルを取り込んでいる
    • url属性を使ってテンプレートファイルを指定
  • <c:param>で指定したデータは、暗黙のオブジェクトparamの中に入っている
    • テンプレートファイル内でEL式を使って${param.name属性名}で取り出すことが可能
  • ${param.content}の中身を表示する部分は<c:out>は使わない
    • EL式のみで指定
    • <c:out> を使うとサニタイジングが実行されるから
      • HTMLのタグをブラウザが認識できないからタグがそのまま表示される

スコープをEL式で取得する。

セッションスコープとアプリケーションスコープのところで作ったJSPのサンプルコードを、EL式を使う形に書き換えてみた。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<% request.setCharacterEncoding("UTF-8"); %>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>セッションスコープのテスト</title>
    </head>
    <body>
        <h1>こんにちは、 <c:out value="${sessionScope.username}" /> さん!</h1>
        <p><a href="session_c.jsp">次のページへ</a></p>
    </body>
</html>
スコープ名スコープから取得(EL式)
リクエスト${変数名}
セッション${sessionScope.変数名}
アプリケーション${applicationScope.変数名}
  • セッションスコープやアプリケーションスコープからデータを取得する場合は明示した方がわかりやすい
    • 暗黙のオブジェクトを指定
  • リクエストスコープにも暗黙のオブジェクトはあるが、ほとんど書かれない
  • ページスコープはWebアプリケーションではあまり使われない

フィルターを作成する方法。

<% request.setCharacterEncoding("UTF-8"); %>

上記のコードを削除したい。その際にフィルターを使う。

EncodingFilterを作成してみる。

STEP
別のパッケージを作成。
STEP
フィルターを作成。

プロジェクト・エクスプローラーでSTEP1で作成したパッケージ上を右クリック→新規→「フィルター」を選択。

STEP
「フィルターの作成」画面を編集。
  • クラス名にEncodingFilterと入力
  • 「フィルター・マッピング」で/EncodingFilterを編集
    • 「URLパターン」を選択
    • パターンのテキストボックスには /*を入力
      • first_webappアプリケーションの全てのサーブレットで適用するフィルターに指定
  • 「Select dispatchers」はすべてのチェックを外す
STEP
EncodingFilterのファイルが作成される。

doFilterメソッドのみ変更(下記コード例)。

STEP
各サーブレットおよびJSPのUTF-8のエンコード設定が不要に。
package test;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class GetServlet
 */
@WebServlet("/GetServlet")
public class GetServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public GetServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //request.setCharacterEncoding("UTF-8");

        String q = request.getParameter("q");

        request.setAttribute("q", q);

        RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/get_result.jsp");
        rd.forward(request, response);
    }

}
public EncodingFilter()

フィルタのインスタンスが生成される際に実行されるコンストラクタ。

init()

フィルタの処理がはじめて実行されるときの処理を定義するメソッド。

doFilter()

フィルタとしての実行内容を定義するメソッド。

destroy()

「(フィルタの処理が不要になったため)フィルタを破棄する」というときの処理を定義するメソッド。

chain.doFilter(request, response);
  • これより前に記述するか後に記述するかで動作が変わる
    • 前:サーブレットが処理を実行する前にフィルタの処理が実行される
    • 後:サーブレットが処理を実行した後にフィルタの処理が実行される

ログを残すフィルタを作成してみる。

package filter;

import java.io.IOException;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

@WebFilter("/*")
public class LogFilter implements Filter {

    public LogFilter() {
    }

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(request, response);

        System.out.println( ((HttpServletRequest)request).getRequestURI() + ":" + new Date() );
    }

    public void init(FilterConfig fConfig) throws ServletException {
    }
}
  • doFilterの引数requestServletRequest型のオブジェクト
    • doGetrequestHttpServletRequest型のオブジェクト
  • 27行目:HttpServletRequestが持つgetRequestURI()を利用してアクセスされた場所を取得する
    • ①:requestHttpServletRequest型にキャスト
    • ②:getRequestURI()を実行する形で記述

以前作成したサーブレットやJSPにブラウザからアクセスしてみると、コンソールの下部に下記のような文字列が表示される。

/first_webapp/GetServlet:Thu Jul 30 12:02:34 JST 2020

イベントを監視する「リスナー」。

STEP
パッケージを作成。

サーブレットやフィルタとは分けておく方が良い。

STEP
リスナーを作成。

プロジェクト・エクスプローラーでSTEP1で作成したパッケージを右クリック→新規→「リスナー」

STEP
「リスナーの作成」画面を設定。
  • クラス名に「PropertiesListener」と入力
  • 「ライフサイクル」にチェック
    • Webアプリケーションが起動したときの処理
STEP
ファイルが作成される。
package listener;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class PropertiesListener
 *
 */
@WebListener
public class PropertiesListener implements ServletContextListener {

    /**
     * Default constructor.
     */
    public PropertiesListener() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see ServletContextListener#contextDestroyed(ServletContextEvent)
     */
    public void contextDestroyed(ServletContextEvent arg0)  {
         // TODO Auto-generated method stub
    }

    /**
     * @see ServletContextListener#contextInitialized(ServletContextEvent)
     */
    public void contextInitialized(ServletContextEvent arg0)  {
        ServletContext context = arg0.getServletContext();

        String path = context.getRealPath("/META-INF/application.properties");
        try {
            InputStream is = new FileInputStream(path);
            Properties properties = new Properties();
            properties.load(is);
            is.close();

            Iterator<String> pit = properties.stringPropertyNames().iterator();
            while(pit.hasNext()) {
                String pname = pit.next();
                context.setAttribute(pname, properties.getProperty(pname));
            }
        } catch(FileNotFoundException e) {
        } catch(IOException e) {}
    }
}
contextInitializedメソッド

リスナーを正しく実行させるために「アプリケーション全般の設定が書かれたテキスト形式のファイル」を用意する必要がある。

META-INFは主にアプリケーションの設定ファイルを格納するために利用する。

string1=abcdefg
string2=hijklmn
string3=opqrstu
string4=vwxyz
  • 変数名=値という形式で1行ずつ設定値を記述
    • =の前後にスペースは不要
  • ①:trycatch内の処理でPropertiesクラスのオブジェクトに渡す
    • 自動で変数名と値に分けてくれる
  • ②:最後に変数名のリストのイテレータを取得
  • ③:ServletContextsetAttributeで1つずつアプリケーションスコープに登録

下記にリスナーが正常に動作することを確認するJSPを作成。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>リスナーのテスト</title>
    </head>
    <body>
        <p>string1 : ${applicationScope.string1}</p>
        <p>string2 : ${applicationScope.string2}</p>
        <p>string3 : ${applicationScope.string3}</p>
        <p>string4 : ${applicationScope.string4}</p>
    </body>
</html>

他のリスナーを試してみる。

下記リスナーを使用してアプリケーションスコープ上にデータが追加登録されたときにログを残すリスナーを作成する。

ServletContextAttributeListener

ファイルの作成方法は前述したものとほとんど同じだが、「リスナーの作成」画面で「属性に対する変更」のみにチェックを入れる。

package listener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;

/**
 * Application Lifecycle Listener implementation class AppScopeLogListener
 *
 */
@WebListener
public class AppScopeLogListener implements ServletContextAttributeListener {

    /**
     * Default constructor.
     */
    public AppScopeLogListener() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see ServletContextAttributeListener#attributeAdded(ServletContextAttributeEvent)
     */
    public void attributeAdded(ServletContextAttributeEvent arg0) {
        System.out.println("アプリケーションスコープに登録しました: " + arg0.getName() + "=" + arg0.getValue());
    }

    /**
     * @see ServletContextAttributeListener#attributeRemoved(ServletContextAttributeEvent)
     */
    public void attributeRemoved(ServletContextAttributeEvent arg0) {
        // TODO Auto-generated method stub
    }

    /**
     * @see ServletContextAttributeListener#attributeReplaced(ServletContextAttributeEvent)
     */
    public void attributeReplaced(ServletContextAttributeEvent arg0) {
        // TODO Auto-generated method stub
    }

}

初めから4つのメソッドが記述されているが、今回は「追加登録」されたときの処理を定義したいのでattributeAdded()のみに内容を追記した。Tomcatを再起動すると下記の内容がコンソールに表示される。

アプリケーションスコープに登録しました: string1=abcdefg
アプリケーションスコープに登録しました: string4=vwxyz
アプリケーションスコープに登録しました: string3=opqrstu
アプリケーションスコープに登録しました: string2=hijklmn

// URLにアクセスすると。。

アプリケーションスコープに登録しました: app_name=テストアプリケーション
/first_webapp/SetAppScopeServlet:Thu Jul 30 13:36:11 JST 2020

ServletContextAttributeEvent (Apache Tomcat 8.0)を参照した。

お問い合わせフォームを作ってみる。

条件
  • 入力画面にフォームを用意
  • フォームに入力された内容をサーブレットで受け取る
  • 受け取ったデータをJSPに渡す
    • 「問い合わせを受け付けました」というタイトルで結果画面を表示
  • 入力内容をそのまま表示
  • すべての項目を必須入力
  • 未入力の内容があった場合はエラー扱い
    • 「エラーがありました」として未入力項目を表示
  • CSSは省略

①:フォームを作成。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>お問い合わせフォーム</title>
    </head>
    <body>
        <h1>お問い合わせフォーム</h1>
        <form method="POST" action="/first_webapp/InquiryServlet">
            <label for="username">氏名</label><br />
            <input type="text" name="username" />
            <br /><br />

            <label for="usermail">メールアドレス</label><br />
            <input type="text" name="usermail" />
            <br /><br />

            <label for="content">お問い合わせ内容</label><br />
            <textarea rows="5" cols="25" name="content"></textarea>
            <br /><br />

            <button type="submit">送信</button>
        </form>
    </body>
</html>
  • 10行目
    • このフォームは入力された情報をPOSTで送る(method
    • 送り先は「http://localhost:8080/first_webapp/InquiryServlet」(action

②:入力された情報を受け取るサーブレットを作成。

  • バリデーション(validation)
    • 入力内容のチェックを行うこと
  • サーブレットの中で入力内容に対して何らかの加工処理をする場合に問題が発生することもあるのでバリデーション推奨
  • 文字列が空かどうかチェックする場合
    • nullチェックとequalsを使った空文字チェックを両方行うのが一般的
package test;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class InquiryServlet
 */
@WebServlet("/InquiryServlet")
public class InquiryServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public InquiryServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String usermail = request.getParameter("usermail");
        String content = request.getParameter("content");

        request.setAttribute("username", username);
        request.setAttribute("usermail", usermail);
        request.setAttribute("content", content);

        RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/inquiry_result.jsp");
        rd.forward(request, response);
    }

}

③:結果画面のビューを作成。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>お問い合わせ結果</title>
    </head>
    <body>
        <h1>お問い合わせを受け付けました</h1>
        <table border="1">
            <tbody>
                <tr>
                    <th>氏名</th>
                    <td><c:out value="${username}" /></td>
                </tr>
                <tr>
                    <th>メールアドレス</th>
                    <td><c:out value="${usermail}" /></td>
                </tr>
                <tr>
                    <th>お問い合わせ内容</th>
                    <td>
                        <pre><c:out value="${content}" /></pre>
                    </td>
                </tr>
            </tbody>
        </table>
    </body>
</html>

おみくじを作ってみる。

条件
  • 入力項目は、氏名の入力欄のみ
  • 「占う!」ボタンをクリックするとPOSTで送信
  • 氏名が未入力の状態で送信した場合は「氏名を入力してください」というエラーを表示
  • 氏名が入力されている場合は、その氏名をそのまま結果画面に表示
    • おみくじの結果を一緒に表示
  • おみくじの結果はランダム
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>今日のおみくじ</title>
    </head>
    <body>
        <h1>今日のおみくじ</h1>
        <form method="POST" action="/first_webapp/OmikujiServlet">
            <label for="username">氏名</label><br />
            <input type="text" name="username" />
            <br /><br />

            <button type="submit">占う!</button>
        </form>
    </body>
</html>

よくあるエラーについて。

HTTPステータス 404 (Not Found)
  • 「指定したページが存在しない」という内容のエラー
  • サーブレットに設定したルーティングの内容とブラウザに入力したURLが合致していない
HTTPステータス 405 (Method Not Allowed)
  • 呼び出したサーブレットに該当のHTTPメソッド(GET, POST)が記述されていないために起こるエラー
  • サーブレットのソースを確認の上でdoGetもしくはdoPostを追記すれば解決
HTTPステータス 500 (Internal Server Error)
  • 「Internal Server Error(内部エラー)」と呼ばれる
  • 例外(実行時エラー)が発生した場合に表示される
  • 画面に表示された内容をググったりして解決するしかない
画面が真っ白になる場合
  • 出力内容が何も指定されていない場合に起こるエラー
    • forwardメソッドの記述忘れ
    • JSPファイルの中身が空

Gitの基本。

Git
  • バージョン管理とはファイルの変更履歴を管理すること
  • Git
    • ファイルの変更履歴を記録・追跡するためのバージョン管理システム
    • Linuxの開発をチームで進めて行くなかで生まれた
    • 編集したファイルを過去の状態に戻したり、今日一日どのファイルのどこを編集したかを表示できる
    • 自分のPC内などローカル環境でのバージョン管理を提供
  • 使うメリット
    • ファイルを変更する際に、バックアップファイルを作成する必要がない
    • 変更する前のファイルの内容にいつでも戻れる
    • 複数人でファイルを変更したり、共同開発を行える
GitHub
  • Gitを使ってバージョン管理しているプロジェクトをオンライン上で共有・管理してくれるWebサービス
  • バックアップ先や、チーム開発の基点となる
  • オープンソースプロジェクトの開発が活発
  • GitHubと同等の機能を持ったWebサービスとして、Bitbucketがある
リポジトリ
  • 1つ1つのバージョンの情報を保存しておく場所(保存先)
    • 「いつ」「誰が」「どのファイルの」「どの箇所を」「どんなメッセージを残して変更したか」
  • バージョン情報の履歴が保存されている
  • ローカルリポジトリ
    • 実際に作業を行うリポジトリ
    • 自分のPC上で作られる
  • リモートリポジトリ
    • チームでのリポジトリ共有やバックアップを目的として作られるネットワーク先のリポジトリ
    • GitHub上に作られる
コミット
  • 1つ1つのバージョンのこと
  • コミットを作成することを「コミットする」と言う
コミットに入っている主な情報
  • リビジョン番号
    • コミットを一意に指定できるIDのような役割
    • コミット時に決定される
    • コミットをやり直した場合にはまったく別のリビジョン番号になる
    • コミットのハッシュ値とも呼ばれる
  • コミットした人
  • コミットした日時
  • コミットしたときのファイル内容の差分
  • コミットメッセージ
    • コミットするときに必須のメッセージ
  • 親コミット(1つ前のコミット)のリビジョン番号
    • 前のコミットを辿っていける
ワークツリーとインデックス
  • ワークツリー
    • Gitでバージョン管理されているフォルダ内のこと
    • ファイルに変更を加えると、ワークツリーに変更が反映される
  • ワークツリーから次のコミットに含めたいファイルの変更箇所を選択することを、「ステージする」と言う
  • ステージされた変更箇所はインデックス(ステージングエリア)に反映される
    • インデックスはローカルリポジトリへコミットする一歩手前
      • コミットする変更箇所を選ぶ段階
  • 最後にコミットを行い、バージョンが1つ進む
    • インデックスにステージされた変更箇所のみ
  • インデックスの意義
    • コミットを行う前に、ワークツリーの変更箇所の中から関連性のある変更のまとまりを選択する

Gitを使う準備。

隠しファイル/隠しフォルダの表示。
$ defaults write com.apple.finder AppleShowAllFiles TRUE
$ killall Finder
コマンドラインでの隠しファイルの確認。
$ ls -a
名前とメールアドレスの設定。
$ git config --global user.name "keiten.kiki"
$ git config --global user.email "hi@kiki.moda"

// リポジトリ毎に設定したい場合
$ git config --local user.name "keiten.kiki"
名前とメールアドレスを確認。
$ git config --global -l
user.name=keiten.kiki
user.email=hi@kiki.moda

実際にGitでバージョン管理してみる。

STEP
フォルダを作成し、移動させる。
$ cd ~/
$ mkdir commit-tutorial
$ cd commit-tutorial
  • ~/commit-tutorial/より下層にあるファイルはすべてバージョン管理下に置かれる
  • 空フォルダは、新規フォルダとしては認識されない
  • 空フォルダを認識させたい場合
    • .keepという名前の空ファイルを作成してそのフォルダ内に配置
STEP
フォルダにGitのリポジトリを作成。
$ git init
Initialized empty Git repository in /Users/KeitenKiki/commit-tutorial/.git/
  • git initコマンドで現在のフォルダ内にリポジトリを作成し、ワークツリーとインデックスを用意
  • 2行目は「空のGitリポジトリを /Users/KeitenKiki/commit-tutorial/.git/ に初期化しました」という意味
  • .git/ :隠しフォルダがリポジトリの実体
    • 直接操作するとリポジトリが壊れるので、触らないように注意
    • その代わりにGitコマンドを使用
STEP
index.htmlを準備
$ touch index.html

touchコマンドで空のファイルを作成。

STEP
index.htmlに追記。
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Gitチュートリアル</title>
    </head>
    <body>
        <h1>はじめてのバージョン管理</h1>
        <p>Gitを使ってバージョン管理する。</p>
    </body>
</html>
  • UTF-8の文字コードで保存できる適当なテキストエディタで上記を上書き保存する(Atomなど)
  • index.html に追記すると、ワークツリーに index.html が追加される
STEP
現在の状況を確認。
$ 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)

git statusコマンドでワークツリーとインデックスの状況をファイル単位で確認。

STEP
変更箇所をステージする。
$ git add index.html

git addコマンドでワークツリーから変更箇所をステージしてインデックスに移動させる。

STEP
現在の状況を確認。
$ git status
On branch master

No commits yet

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

	new file:   index.html
STEP
コミットする。
$ git commit -m "first commit"
[master (root-commit) 9aea317] first commit
 1 file changed, 11 insertions(+)
 create mode 100644 index.html
  • git commitコマンドでコミットする(バージョンを作る)
  • ""内はコミットメッセージ
STEP
コミット履歴を確認。
$ git status
On branch master
nothing to commit, working tree clean

新規ファイルなどもない状態に。

$ git log
commit 9aea31708b0177193e1b7dd82a3acfde3ffdf4fe (HEAD -> master)
Author: keiten.kiki <hi@kiki.moda>
Date:   Thu Jul 30 19:05:32 2020 +0900

    first commit
  • git logコマンドでコミット履歴を確認
  • 4つの情報が表示されている
    • コミットのリビジョン番号
    • コミットした人
    • コミット日時
    • コミットメッセージ
STEP
さらにファイルを更新。
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>Gitチュートリアル</title>
    </head>
    <body>
        <h1>はじめてのバージョン管理</h1>
        <p>Gitを使ってバージョン管理する。</p>
        <img src="git-logo.png" alt="git logo">
    </body>
</html>

<img>タグで画像を追加してみた。

STEP
現在の状況を確認。
$ 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

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

	git-logo.png

no changes added to commit (use "git add" and/or "git commit -a")
  • Changes not staged for commit
    • 変更されたがステージされていないファイル
  • Untracked files
    • 新規追加のファイル
STEP
前回のコミットとの差分を確認。
$ git diff
diff --git a/index.html b/index.html
index 6e638f6..7609760 100644
--- a/index.html
+++ b/index.html
@@ -7,5 +7,6 @@
     <body>
         <h1>はじめてのバージョン管理</h1>
         <p>Gitを使ってバージョン管理する。</p>
+        <img src="git-logo.png" alt="git logo">
     </body>
 </html>
  • git diffコマンドでワークツリーとインデックスを比較してファイル同士の差分を抽出
  • 追加された部分は緑色で表示される
  • 削除された部分は赤色で表示される
  • 新規ファイルは差分の比較対象にはならない
  • git diff --cachedコマンド
    • インデックスとローカルリポジトリの基準コミットとの差分を確認したい場合に使用
STEP
ステージする。
$ git add .

ファイル名の代わりに.を入力することで、新規追加や変更されたファイルをすべてステージさせることが可能。

STEP
現在の状況を確認。
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   git-logo.png
	modified:   index.html
STEP
ステージされた変更分をコミットする。
$ git commit -m "add git-logo image"
[master 08ecfa5] add git-logo image
 2 files changed, 1 insertion(+)
 create mode 100644 git-logo.png
STEP
コミット履歴を確認。
commit 08ecfa55cf713925556df711088435b72b7f85a2 (HEAD -> master)
Author: keiten.kiki <hi@kiki.moda>
Date:   Thu Jul 30 19:32:36 2020 +0900

    add git-logo image

commit 9aea31708b0177193e1b7dd82a3acfde3ffdf4fe
Author: keiten.kiki <hi@kiki.moda>
Date:   Thu Jul 30 19:05:32 2020 +0900

    first commit

良いコミットメッセージ。

短い (50 文字以下での) 変更内容のまとめ

必要に応じた、より詳細な説明。72文字程度で折り返します。最初の 行がメールの件名、残りの部分がメールの本文だと考えてもよいでしょ う。最初の行と詳細な説明の間には、必ず空行を入れなければなりま せん (詳細説明がまったくない場合は空行は不要です)。空行がないと、 rebase などがうまく動作しません。

空行を置いて、さらに段落を続けることもできます。

– 箇条書きも可能

– 箇条書きの記号としては、主にハイフンやアスタリスクを使います。 箇条書き記号の前にはひとつ空白を入れ、各項目の間には空行を入 れます。しかし、これ以外の流儀もいろいろあります。

5.2 Git での分散作業 – プロジェクトへの貢献

今日の反省と明日の目標。

今日は朝から首を寝違えていて最悪のスタートだったが、頭を動かすと痛むので逆に作業に集中できた。JSPとサーブレットを一通りやってみて、ほんの少しだけ理解できたと思う。具体的には真っ新な状態からコードは書けないけど、参考書を見ながらなら一応でき上がるレベル。一からスラスラ書けたらカッコいいに違いないが、そこに拘ったらいつまで経ってもポートフォリオができないので、参考書を見ながらでも解けたら次に進むようにしている。

Gitを触ってみた感想としては同じコマンドラインツールのMySQLを触っている感じと似ていた。裏で何が起こっているのか分かりにくいのは共通している。

明日はGitの続き、GitHubからやっていこうかと思います。

閉じる