【python】pandas使いました

こんにちは。 梅雨も明け、暑い日が続きますね・・・ 晴れていることは嬉しいですが、気軽に外を歩けないのが辛いです。

相変わらずドラムの練習もしているのですが、車に荷物を乗せスタジオまでに持ち運ぶ頃には汗だくで満身創痍です。

とはいえ、好きなことですので暑さに無理しない程度に?楽しんでいこうと思います!

はじめに

急に変わってお仕事の話ですが、昨年からAIに関する業務に携わっていて、最近ではオープンデータを活用して予測モデルを作っています(業務秘密もあるので、超ざっくりしてます笑)。

業務に携わる中で、タイトルの"pandas"を活躍しているわけですが、pandasの基礎のない私は闇雲にググりながらなんとか・・・!動作させていました。

作業が一段落したので、復習も兼ねて今回はこのpandasについて基本的なことをまとめてみます。

pandasとは

概要

Package overview — pandas 1.3.0 documentation

pandas is a Python package providing fast, flexible, and expressive data structures designed to make working with “relational” or “labeled” data both easy and intuitive.

上記はPandasの公式から引用しました。

ざっくり翻訳すると、リレーショナル、ラベルデータなどのデータ構造に対してのデータ分析を可能とするpythonパッケージであるとのことです。

"リレーショナル"、"ラベルデータ"についての詳細は割愛しますが、どちらも共通して列、行で構成される2次元の表データと考えることができるかと思います。

f:id:avicenxz:20210722105109p:plain

pandasでは、「DataFrame」という2次元のデータを格納するオブジェクトを用いて、表形式のデータに対していろいろな処理を施すことができます。

ちょいと話がそれますが、AIで何か解析を行いたい!となった場合、いきなりAIにデータを読み込ませるのではなく、AIに読み込ませることができる形に加工してあげる※必要があります。

厳密にいうと、「AIなどのプログラムにおいて、学習用のメソッドの引数に相応しい形式に変換する必要がある」と言った方が正しいのかな?と思ってますが、そんな時に、このpandasが大活躍するわけですね。

今後も、私はAIについてもっと触れていきたいと思ってますので、このpandasとは長い付き合いになりそうです。

DataFrame, Seriesについて

概要

"DataFrame"という2次元のデータを格納するオブジェクト、"Series"は、1次元のデータを格納するオブジェクトです。

csvexcel形式などのデータをDataFrame形式として読み込むことで、任意の行列のデータを抽出したり、列ラベルの情報を取得したり、新しい列・行を追加したり・・・といろんなことができます。

その、いろいろな操作を覚える前に、まずはDataFrame, Seriesの構成について押さえておく必要があります。

構造

以下は、DataDFrame, Seriesの構成をまとめたものになります。

f:id:avicenxz:20210722105549p:plain

名称 意味
columns 列名(列ラベル、ヘッダー)
index 行名(行ラベル)
values 実際のデータの値

DataFrameのメソッドは、このcoumnsやindexを指定した操作があるのでこれらの用語はしっかりと抑えておきましょう(自分に言ってます笑)。

また、seriesは1次元のデータなわけですが複数集まることで、DataFrame(2次元)になるという関係も覚えておくと良いと思います。

コード

今回は、csvファイルDataFrameに変換する方法を記述します。

import pandas as pd

df = pd.read_csv('data/src/sample_pandas_normal.csv', index_col=0)
print(df)
#           age state  point
# name                     
# Alice     24    NY     64
# Bob       42    CA     92
# Charlie   18    CA     70
# Dave      68    TX     70
# Ellen     24    CA     88
# Frank     30    NY     57

超ざっくり解説ですが、 index_colは、indexとなる列を指定します(上記のコードでは、"name"列を指定)。

また、上記では、"name", ""age", "state", "point"が自動で行ラベルに指定されていますが、"header=None"という引数を追加すると これらは一つのデータ(values)になります。
→代わりにcolumnsには、0, 1, 2・・・と連番で付与される

参考

pandasのAPIリファレンス(read_csv)

終わりに

ここまで見てくださりありがとうございました! 次回は、DataFrameで実際に行った加工方法についてまとめてみようと思います。

【AWS】静的webホスティング

はじめに

こんにちは、AWSクラウドラクティショナー資格試験に向けて勉強中の筆者です。

今回も勉強から少し脱線して、AWSの機能であるS3を用いてwebページを配信する方法(静的webホスティングを調べてみました。

自分はweb専門のエンジニアではないのですが、この静的webホスティングの機能をうまく使えば、アプリのAPIリファレンスなどを自動(別のサービスと組み合わせた上で)で配信するといったこともできるのではないか?

と考え、ちょいと調べてみたいと思いました。

今回の記事では、以下二つについてまとめます。

- Webを配信する形態の基礎的な概要 - AWSの機能であるS3とRoute53を用いた静的webホスティングの方法

静的コンテンツと動的コンテンツについて

特徴

静的コンテンツ、動的コンテンツは、webブラウザを通じて、html, css, javasctiptなどの情報を取得する仕組みのことを指します。

違い

webサーバーソフトウェアがあるかないかが、一番大きな違いかなと思います。

webサーバーソフトウェアとは、webブラウザからのhttpリクエストに対してhtmlファイルや画像などを返す機能の持つソフトを指します。

代表的なwebサーバーソフトとしてapatch、nginxなどがあります。

webサーバーソフト上では、html, css, javascriptといったブラウザで動作する言語ではなく、python, java, などのプログラムによって動作します。

動的コンテンツではこのwebサーバーソフトが存在する一方で、静的コンテンツではwebサーバーソフトは存在しません。

動的コンテンツではサーバー側でプログラムを動作できるため、別途データベースサーバーやAPIサーバーなどと連携するといった柔軟な構築も可能です。

f:id:avicenxz:20210625144351p:plain

webアプリ開発経験の乏しい筆者は、webアプリといったら動的コンテンツを指すものだと思ってましたが、これでちゃんと覚えました!笑

静的webホスティングとは?

AWSのS3を用いて、静的コンテンツを配信するための仕組みです。

html, javasctipなどのファイルをS3に配置しておけば、ブラウザ経由で、静的コンテンツを表示することができます。

Amazon S3 を使用して静的ウェブサイトをホスティングする - Amazon Simple Storage Service

今回作るもの

概要

今回は、AWSのS3に静的webホスティングを構築します。

S3へのアクセスには、AWSのRoute53の機能を使用して独自のドメインでのアクセスを試みます。 なお、AWSでもドメイン取得は可能ですが、今回はfreenomというドメイン取得サービスを用います。

f:id:avicenxz:20210622190803p:plain

作業

作業概要

ドメイン取得

freenomでドメインを取得します。

S3の設定

S3を用いて、静的webホスティングの設定を行います。

Route53の設定

以下を実施します。

  • Route53で取得したドメインの、ルーティング設定
  • freenomで取得したドメインを、"Route 53 ネームサーバー"に委任する設定

作業詳細

ドメイン取得

長いので折り畳みます! 以下、freenomのサイトにアクセスすると、取得したいドメイン名を入力する欄が出てきます。

www.freenom.com

ここで、取得したいドメイン名を入力して「利用可能状況をチェックします」を押下すると、入力したドメインが使用できるか結果が表示されます。

f:id:avicenxz:20210618143340p:plain

.tk, .ml. ga, .cf, gqとあまり馴染みのないトップレベルドメインに関しては無料(12ヶ月)で取得できますので、とりあえずお試しでドメインを取得したい場合は、こちらのを取得すると良いのかと思います。

使用可能なドメインを選択して、購入画面にてドメインを購入します。

S3の設定

長いので折り畳みます! バケットを作成」を押下して、新規にバケットを作成します。

f:id:avicenxz:20210621205142j:plain
s3

バケット名称は、後述のRoute53で設定するレコード名と同じになるように設定する必要があります。

バケット名称例: "取得ドメイン名.tk"

バケットを作成できたら、任意のhtmlファイルをアップロードします。以下の図では、index.htmlというファイルをアップロードしました。

f:id:avicenxz:20210621211630j:plain

このファイルに対して、静的webホスティングの設定を行います。

バケット→プロパティ→静的webホスティングで、「編集」を押下すると、静的webホスティングに関する設定ができます。

ここで、以下のように設定して「変更の保存」を押下します。

  • 静的webホスティング:有効にする
  • ホスティングタイプ:静的webホストをホストする
  • インデックスドキュメント:先程アップロードしたファイル名(index.html)

ここまで完了すると、先ほど静的ウェブサイトホスティングの「編集」を押下した画面で、バケットウェブサイトエンドポイントのURLが表示されます。

f:id:avicenxz:20210621212322j:plain
HOSTING

これで無事、静的ウェブサイトホスティングの設定が完了しました。

バケットウェブサイトエンドポイントのURLにアクセスすることで、先ほどアップロードしたファイル(index.html)にアクセスすることができます!

Route53の設定

Route53で取得したドメインのルーティング設定

長いので折り畳みます! freenomで取得ドメインしたドメインを、先ほど設定したS3の静的webホスティングのURLにルーティングしてあげます。

AWSのRoute53の画面で、「ホストゾーンの作成」とあるので、押下します。

表示された画面で以下のように設定し、「ホストゾーンの作成」を押下します。

f:id:avicenxz:20210624141548j:plain

ホストゾーンを作成するとタイプSOA、タイプNSのレコードが1つずつ生成されますが、ここにタイプAのレコードを新規に追加します

以下の画面で、「レコードを作成」を押下します。

f:id:avicenxz:20210624142047j:plain

レコードの作成画面では、以下のように入力します。

  • レコードタイプ:A-IPv4アドレスと〜
  • エイリアス:ON
  • AWS各サービスのエイリアス:S3ウェブサイトエンドポイントのエイリアス
  • リージョン:作成したS3と同じリージョン
  • S3エンドポイント:S3で設定したバケット名が表示されるので、それを選択する※

※ルーティングさせたい「レコード名」と、S3で設定したバケット名が同じ出ないと表示されないので注意!!

全て入力できたら、「レコードを作成」ボタンを押下して作業完了です。

freenomで取得したドメインを、"Route 53 ネームサーバー"に委任する設定

長いので折り畳みます! freenomで取得したドメインはRoute53のサーバーの情報を持っていないため、Route53のネームサーバーを教えてあげる必要があります。

まず、「Route53の設定」でホストゾーンを生成した際に、自動で作られたタイプNSのレコード値をメモします。

次に、freenomで取得したドメインに対して、メモしたRoute53のネームサーバーの設定を行います。

services→MyDomainsと選択すると、取得したドメインを確認できる画面に移動します。 この画面で、取得したドメインで「ManageDomain」を押下します。

f:id:avicenxz:20210624144132j:plain

ManagementTools→NameServersと選択すると、以下のような画面に遷移しますので、「Use custom nameservers (enter below)」を選択し、NameServerに先ほどメモしたRoute53のネームサーバのドメインを入力します。

以下の図では、既にネームサーバーのドメインを入力しているものになります。

f:id:avicenxz:20210624144348j:plain

最後に、ChangeNameServerを押下して終了です。

ここまで実施して、取得したドメインをブラウザに入力することで、S3で設定したURLにアクセスできるはずです。 お疲れ様でした!

最後に

この静的webホスティングの機能をうまく使えば、アプリのAPIリファレンスなどを自動で配信するといったこともできるのではないか?

GitHubActionsなどと連携して上記トライしてみようと思います!

余談ですが、今回の記事は文章量が多すぎたと思いました。。。随時見直して、おかしな記述あれば修正します。

【ネットワーク】DNSについて!

はじめに

こんにちは、最近GitHubActionsで、自動化の技術に感銘を受けたのですが、自分もガンガン自動化できるノウハウを手に入れたい・・・! と思い、AWSの資格取得をしてみようと考えました。

AWS Developer Assosiateあたり目標にします! 目指せDevOpsエンジニア!です!

ということで、前身となるAWS Cloud Practitionerの資格から勉強を始めてみました。 AWSのコアサービスの一つであるRoute53を勉強する際に、DNSってよく理解していないと思ったのでこちらを理解した内容を記事にまとめることにしました。

と、自動化の勉強をすると言っていて、「DNS」とのことで全然関係ない記事を書くわけですが、寄り道しながらもスキルアップを図っていこうと思います!

ドメインについて

概要

ドメイン(Domain)とは、インターネット上での住所を示すものです。 例えば、ブラウザを立ち上げて

https://www.google.com

と入力すると、googleの検索フォームが表示され、検索機能を使用することができます。

この"google.com"にあたる部分をドメインと呼び、この住所に該当する情報を受け取ることができます。

IPアドレスとの関連

本来、インターネット上の住所というと、このIPアドレスが該当します。 このIPアドレスは以下のように、1-255までの数字を4つ組み合わせた数字を用いて使用します。

172.217.175.110

先ほどブラウザではIPアドレスを入力することでも同様に情報を取得できます。 しかし、上記のように数字で表現すことでアドレスを理解しづらいという問題があり、ドメインという概念が登場しました。

本ブログでもドメイン名がありますが、ここがIPアドレスで表示されていたら、正しくそのサイトにアクセスできているのか?怪しいサイトにアクセスしているんじゃないのか?不安になりますよね。

※もちろんドメインが表示されていても、それが必ずしも安全なサイトであるかは限らないわけですが!

DNSサーバーについて

概要

DNS(Domain Name System)サーバーとは、ドメイン名とIPアドレスを対応ずける仕組みを提供するサーバーです。

DNSサーバーの種類

名称 役割 補足
DNSルートサーバー DNSキャッシュサーバーが最初に問い合わせするサーバー。最上位となるドメインIPアドレスを返却する。 全世界に13しか存在しない!
DNS権威サーバー DNSキャッシュサーバーから、リクエストとして受け取ったドメインに紐づくIPアドレスを返却する。
DNSキャッシュサーバー クライアントPCからの問い合わせに対して、権威DNSサーバーにリクエスト(ドメイン)を送る。
DNS権威サーバーから応答として受けたIPアドレスをクライアントPCに返却する

仕組み

以下の図では、"drum.co.jp"にアクセスする様子を示しています。

まずクライアントのPCは、キャッシュサーバーに対して"drum.co.jp"のIPアドレスを教えてもらうよう問い合わせをします(1.)。

通知を受けたキャッシュサーバーは、ルートサーバに対して問い合わを行います(2.)。

ルートサーバーでは"jp"の権威DNSサーバーのIPアドレスのみを知っているため、キャッシュサーバーはこのIPアドレスを受け取ります。

この時点で"drum.co.jp"のIPアドレスはわからなく、"jp"サーバー、"co.jp"サーバーのように権威DNSサーバーは階層構造となっているので、キャッシュサーバーは最下位のドメインを取得するまで権威DNSサーバーに問い合わせを続けます

最終的に"drum.co.jp"のIPアドレスを取得することができたら、もともと問い合わせを受けていたクライアントのPCにIPアドレスを返却します(8.)。

このIPアドレスを用いて、クライアントでは"drum.co.jp"のドメインのサーバーにアクセスすることができます(9.)。

f:id:avicenxz:20210606161655p:plain

補足

このように複数のDNS権威サーバーを使用してIPアドレスを管理している理由の一つに「負荷分散」があります。 この記事では特に触れませんが、元々は一つのサーバが"HOSTS"というファイルを用いてドメイン名とIPアドレスの対応付けを行っていました。

インターネットに接続したい人はこのHOSTSファイルを自身のPCにダウンロードすることで、ドメイン名を使用したインターネット接続を行っていました

しかし、一つのサーバで管理するのが大変になったため、このように複数のDNSサーバを用いて管理するようになったそうです。

ちなみにですが、このHOSTSファイルはLinuxMacなどだと/etc/hostsに、windowsだとC:\Windows\System32\drivers\etcに格納されています。

自分のPCには数行しか記載されてないですが、DNSの概念がないとこのHOSTSファイルにびっしりと通信先のサーバーのIPアドレスが記載されていたのかな?と思います。 管理が非常に大変そうですね・・・(小並感)。

最後に

今回は、DNSの最低限の仕組みを記述しました。

せっかくですので、今度はRoute53で実際に構築したDNSのルーティングをコマンドなど含めて紹介してみようと思います!

【機械学習】Appleの機械学習をいじっていきます!

はじめに

こんにちは。
「ドラムのフォームを定量的に把握し、技術向上をサポートしたい!」

というマインドを抱えている筆者です。

突然ですがフォームを定量化するためには、以下が必要であると考えております。
①骨格を検出する技術
②検出した結果を表示する環境

②は、ここ一年ネイティブアプリ(iOS, swift)の技術取得を「Myトレ」を通じて身に着けました。
①は、まだまだ何も力がついていない状態ですので、これから身に着けていこうと思います。

さて、①に対してどうアプローチできるか?ですが、Apple社が提供している機械学習を用いて「骨格検出」ができることがわかりました。

以下は、サンプルプログラムにより、アプリで骨格検出した画像になります。

実際に検出した結果(骨格の位置)を、ドラムの上手い人と比較することで何が足りないのか?定量的に評価できると考えております(というよりしたい)。

ということで!今回は「骨格検出」するためのノウハウをまとめていきたいのですが!その前に、Apple社の提供している機械学習の概要についてまとめようと思います。

前提 - 機械学習モデルとは?

機械学習では「機械学習モデル」というものが存在します。
機械学習モデル」とは、入力データに対すてモデルの予測により何らかの結果(出力データ)を算出してくれるものになります。
→モデルの予測によって人間が複雑なプログラミングをする手間を省ける(などのメリットがある)

f:id:avicenxz:20210206102422p:plain

この機械学習モデルの学習方法には大きく3つあります。
教師あり学習
教師なし学習
強化学習

詳細は割愛しますが、それぞれ「大量に集めた学習データから共通する特徴を抽出する」ことでモデルを作成します。


さて、ここからが肝心です。
冒頭で「骨格検出」と言うキーワードを出しましたが、Apple社では「骨格を検出するための機械学習モデル」を既に公開しています。
そして、その機械学習モデルをプログラムで実装するためのAPIも用意しています。

つまり、自分で「骨格検出」を行う「機械学習モデル」を一から頑張って作る必要はないのです。
機械学習モデル」による予測を行うプログラムも一から作る必要はありません。


エンジニアは上記の「API」の仕様さえ抑えれることができれば、機械学習モデルの効果を体感することが可能となります。
→とはいえ、そのAPIの仕様を抑えるのに苦労している筆者


前提が長くなりましたが、次のセクションではその「API」について解説します。

機械学習を提供する二つの「API

種類

API 特徴 事前のモデル準備 ネットワーク接続
CoreML API 「CoreMLモデル」による予測をサポートするAPI 必要 オフラインで動作可能
機械学習API 事前に「CoreML」を用意しなくても、機械学習モデルによる予測をサポートするAPI 不要 オンラインで動作可能

CoreMLとは?

ここで、「CoreML」とはAppleで定義している「機械学習モデル」になります。
このモデルに対してCoreML APIを用いることで、CoreMLによる予測を実施できます。

このCoreMLは自作することも可能(後述)ですが、以下のサイトで学習済みのものも入手することができます。

developer.apple.com

★冒頭であげた写真は、「PoseNet」という骨格検出可能とするCoreMLモデルを使って、画像に写っている人の骨格を検出しています(サンプルプログラム動かしただけです)。

オンラインで動作可能とは?

機械学習APIでは、事前に「CoreML」を用意しなくても良いと記述しています。

また、ネットワーク接続で「オンラインで動作可能」と記述していますが、「CoreMLモデルによる予測」はサーバで実行するということになります。

以下イメージ図書いてみました。

f:id:avicenxz:20210206103911p:plain

インプットとなる情報はアプリ側で収集して、そのデータをサーバに送ります。
あくまで想像ですが、サーバの中にある機械学習モデルが受け取った入力データに対していい感じに予測してくれて、アウトプットのデータをユーザ側に応答を返すといった感じですかね。

機械学習APIの種類

名称 概要
Vision 画像や動画に対する処理や分析
Natural Language テキスト分析
Speech 言語の音声認識
Sound 言語以外の音の分析

↓余談
私がローンチしたアプリ「Myトレ」では、「Speech」を使い録音した音声をテキストに変換しています

上記で取得した「テキスト」が、アプリに登録されている種目と一致する場合、その種目を1タスク分のデータとしてFirebase側にインサートしている、そんな感じの仕組みを実装しております。


ちなみに、機械学習APIはオンライン環境下でないと使用できないと記述しましたが、「Myトレ」もオンラインでないと種目の登録はできないようにしています。

CoreMLモデルの作成方法

作成済みモデルを取得する(自分では作らない)

先ほども記述しましたが、以下で入手できます。
developer.apple.com

CreateML - 自身でオリジナルのCoreMLモデルを作る

Xcodeを使用して、CoreMLモデルを作成できます。
筆者も少し触れたことがあるのですが、こちらについては今度!別の記事でまとめようと思います。

以下のリンクでCreateMLについて紹介してくださっています。
developer.apple.com

CoreMLコンバータ - 学習済みモデルを「CoreML」に変換する

どんな学習済みモデルを「CoreML」に変換できるのかは、必要な時が来たら調査しようと思います・・・

どちらのAPIを使えば良い?

超ざっくりですが、以下のような感触ですかね。

・自分でオリジナリティあふれる予測をしたい、場合
 → coreML API

機械学習APIで求めている予測ができる、かつオンラインによる動作を許容する、場合
 →機械学習API

さいごに

CoreML APIの基本を抑える旅にでます。

【swift】AVFoundationを使って、動画の撮影を行う!

こんにちは。
先日以下のような記事を書かせていただきました。

kz-ike.hatenablog.com


前回は、AVFoundationに関する概念のお話でしたので、今回の記事では「動画を撮影する際に使用するクラス、及び必須設定項目」についてまとめようと思います。

※動画を追加する設定項目についてのみ説明するため、sessionクラスへinputを追加するや、session自体の開始といった方法は省略します。

最初に

動画を撮影して表示しるソースは以下に格納しました。

sampleAVFoundation/avFoundation at main · d-ike99/sampleAVFoundation · GitHub

AVFoundationに関するコードは、「ViewController.swift」に全て記載してます!

動画を撮影するのに必要なクラス

クラス名 概念
AVCaptureSession インプット、アウトプットに関する「セッション」を制御する
AVCaptureDeviceInput AVCaptureSessionの入力データとして定義するもの
AVCaptureVideoDataOutput インプットで取得した動画に対して、「記録」、「1フレーム毎へのアクセス」を可能とするアウトプットクラス

各クラスで必要な設定

AVCaptureSession

設定項目
変数 説明
sessionPreset AVCaptureSession.Preset アウトプットの解像度、ビットレートを定義する
補足

下記リンクで、Presetに定義できる変数がまとめられています。
それぞれの変数がどういったシーンで有効か全て把握できてませんが、上記のgithubでのサンプルプログラムでは「hd1920x1080」を指定しています。

https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture

AVCaptureDeviceInput

設定項目
変数 説明
device AVCaptureDevice インプットとしてどのデバイス(マイク、カメラなど)を使用するか定義する
補足

動画を撮影する際に指定するコードです。

guard let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front) else {
    return
}

// インプットの定義
guard  let createInputInfo = try? AVCaptureDeviceInput(device: captureDevice) else {
    return
}

AVCaptureVideoDataOutput

設定項目
変数 説明
videoSettings [string: Any] 撮影した動画(画像)のフォーマットを設定する
alwaysDiscardsLateVideoFrame bool 「撮影したフレーム」のデータを、すぐに削除せずにメモリに残しておくかを指定する。単純に動画を表示するだけなら基本trueで問題ない
setSampleBufferDelegate - ・sample buffer(撮影した動画の一枚一枚のフレーム情報)の出力先の指定(delegateを定義する)
・上記delegateを呼び出すためのqueueの指定
補足

今回の記事では特に触れませんが、「マルチスレッド」の概念を抑えておくとコードを読みやすいです。
今回の動画を撮影するケースですと、以下のようなスレッドが登場すると思います。

①動画を撮影するスレッド
②撮影した動画の一枚一枚のフレームを出力するスレッド(setSampleBufferDelegateで定義するqueue)

videoOutput.setSampleBufferDelegate(self, queue: sessionQueue)

③「sample buffer」として取得した画像を、「画面に表示するため」のスレッド

DispatchQueue.main.sync {
    self.dispFrame(didCaptureFrame: image)
}


↓マルチスレッドを勉強した参考リンク
【Swift】Grand Central Dispatch (GCD)とOperationQueue まとめ - Qiita

さいごに

今回は、動画の撮影方法のみ言及しましたが、動画を保存するとなると別途手順が必要です。
私たちが何気なく使っている「カメラアプリ」もいろんな技術が詰まっていると改めて実感しました・・・!

【git】マージを理解する - ブランチのお供に!!

はじめに

本日は、マージの種類・方法についてまとめます。

先日、【git】"git-flow"を齧る - ドラムと筋肉とプログラミングという記事を書かせていてだきましたが、gitで複数のブランチを管理していくとなると「ブランチを切る・マージする」といった作業が必要になります。


マージの方法というのはいくつかありまして、マージに関して検索すると、「rebase」、「merge」、「fast-foward」といった用語が登場します。

それぞれどういった特徴なのか理解していないと、なんとなーく使用してしまいます。そしてコミットログが汚くなります。

コミットログが汚くなるのを避けるために、git-flowなどを用いてブランチを管理するためにも、マージの方法について理解していきます。

mergeとは?

概念

あるブランチの作業履歴(コミット)を、自分のブランチに取り込むこと

種類

  • Fast-fowardマージ
  • 3wayマージ(Non-Fast-fowardマージ)
  • rebase

いきなり「マージ」とは関係のなさそうな単語が登場しましたね・・・
しかし、一つ一つ見ていけば決して理解し難いものではないです。それぞれ説明していきます。

Fast-fowardマージ

概念

ブランチの「ポインタ」を"前に進める事"によるマージ

解説

概念だけ聞かされると何を言ってるかイメージしづらいと思います。
実際に作業するシーンも踏まえて説明します。


1. 新たなブランチの導入
 masterブランチで「バグ」が見つかったため、ブランチを切り(hotfix)修正した(C4コミットを切った)
https://git-scm.com/book/en/v2/images/basic-branching-4.png

2. masterブランチへの反映
 hotfixブランチでの修正作業が完了したため、masterブランチをhotfixブランチと同じ状況にしたい

// mergeコマンドの実行
$ git checkout master
$ git merge hotfix

Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

3. 結果
 masterブランチのポインタ、すなわち「コミットの位置」がhotfixと同じ場所に移動しました。
https://git-scm.com/book/en/v2/images/basic-branching-5.png

補足

上記のような例を出しましたが、言い換えると派生元のブランチが「更新されることがないことを見込める」の時に使用可能です。
上記の例で、hotfixで修正中にmasterブランチでも別途コミットを切ってしまった場合は、以下の3wayマージを使用する必要があります。

3wayマージ(Non-Fast-forwardマージ)

概念

3wayは3つのコミットを表しています。

①マージ元ブランチのポインタに該当するコミット
②マージ先ブランチのポインタに該当するコミット
③①、②の共通祖先となるコミット

「①と③の差分」と、「②と③の差分」をマージ元ブランチに取り込む方法を「3wayマージ」と言います。

解説

こちらも実際に作業するシーンも踏まえて説明します。


1. 新たなブランチの導入

  • masterブランチでバグが見つかったので修正用のブランチを切った(iss53)
  • iss53ブランチにて修正作業を実施した(C3, C5コミットを切った)
  • masterブランチで非バグの修正を行った(C4コミットを切った)。

https://git-scm.com/book/en/v2/images/basic-merging-1.png


2. masterブランチへの反映
 iss53ブランチでの修正作業が完了したので、masterブランチにマージをします。
 コマンドは「fast-fowardマージ」の時と同様ですが、ブランチを切ったコミット位置(C2)からマージ元ブランチ(このケースだとmaster)のコミットが進んでいます。

 そのため、masterブランチの差分(C2-C4の差分)とiss53ブランチの差分(C2-C5の差分)をそれぞれ抽出し、結合したものをmasterの新しいコミットとします(3.結果のC6)。

// mergeコマンドの実行
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

3. 結果
3wayマージをした結果になります。
iss53ブランチのコミット位置は変わりませんが、masterブランチはiss53ブランチのコミットを取り込んだ結果として、C6コミットが新しく生成されました。

このC6は3wayマージにより自動的に生成されるコミットでして、「マージコミット」といいます。

https://git-scm.com/book/en/v2/images/basic-merging-2.png

補足

コンフリクトについて

3wayマージなどで、それぞれのブランチの「共通の親」からの差分の箇所が同一となる場合、コンフリクトが発生します。

この場で詳細な修正手順は省きますが、
競合した該当ファイルはマージ元、マージ先の差分のどちらか(両方も可能)をファイルに取り込むよう修正して、コミットしてあげる必要があります。
先ほど、3wayマージでは「マージコミット」が自動的に生成されると話しましたが、コンフリクトした場合は手動で「マージコミット」を切る必要がある、ということがポイントです。

リベース

概念

基本は、マージと同じ考えです。

あるブランチの作業履歴(コミット)を、自分のブランチに取り込むこと

解説

こちらも実際に作業するシーンも踏まえて説明します。


1. 新たなブランチの導入

  • masterブランチで新たな機能を追加したいため、ブランチを切った(experiment)
  • iss53ブランチにて新規機能を追加した(C4コミットを切った)
  • masterブランチでバグが見つかったので修正した(C3コミットを切った)

https://git-scm.com/book/en/v2/images/basic-rebase-1.png


2. masterブランチの取り込み
 masterブランチでのバグ修正作業が終わったため、experimentブランチにマージします。

// rebaseコマンドの実行
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command


3. 結果
リベースした結果になります。

https://git-scm.com/book/en/v2/images/basic-rebase-3.png

experimentブランチのC4コミットは、C4'コミットという形でmasterブランチの先頭に切られました。

experimentブランチ上にmasterブランチが存在するような形になりましたので、「Fast-fowardマージ」により「masterブランチ」を「experimentブランチ」に移動することが可能となりました。

3wayマージと違いコミットが一直線となっているため見た目も綺麗です。

補足

リベースの多用はNG

一度リモートリポジトリにプッシュしたコミットに対してリベースは絶対に実施してはならないです!!

3.結果で少し触れましたが、リベースによって複数のコミットログをまとめた場合でも、それがプッシュ済みのコミットである場合、後で復活してしまう恐れがあります(要はコミットログがめちゃくちゃになって履歴の確認が困難になってしまう)。

そのほかにも、リベースを使用してはいけないと感じたケースがありますが、それはまた次の機会にご紹介したいと思います。

さいごに

git-flowなどのブランチ戦略を導入するとなると、「ブランチを切る」、「マージする」という作業がいやというほど登場してきます。

マージするときに、どのマージ手法を選択すれば良いか?その都度迷わないように、ブランチを運用する前に上記の内容をしっかり抑えておくと良いと思います。

【git】"git-flow"を齧る

はじめに

本日はタイトルの通り、"git-flow"についてご紹介します。

gitでは簡単にブランチを切れて便利ですが、何も考えずにとりあえずブランチを切って作業してしまうと後の管理が困難になってしまいます。

そこで、"新規機能開発"、"リリース"といったソフトウェアの開発作業における"作業工程(目的)毎"にブランチを切って、それぞれのブランチで作業を遂行する
というブランチ戦略の考えが登場しました

この"Git-flow"は、gitのブランチを管理するプライグインでして、ブランチ戦略、リリース管理をサポートするものとなっています。

筆者も「Myトレ」などでGitを使用していてこの"Git-flow"の考えはなんとなく取り入れていたのですが、なんとなくで留まってしまっていたため改めて理解を深めたいと思います。

本記事では、"git-flow"におけるブランチ戦略の考えと、実際の作業工程で具体的にどのような作業をするのか?をまとめます。

参考

「Vincent Driessen氏」が"A successful Git branching model"という記事にて紹介しています。

原文:A successful Git branching model » nvie.com
翻訳:見えないチカラ: A successful Git branching model を翻訳しました

"Git-flow"で用いるブランチの説明

ブランチの種類

  • メインブランチ

メインブランチは、"開発"と"リリース"における最新の状態を管理します。サポートブランチと違い、永久的に管理します。

ブランチ名称 分岐元、マージ先 役割
master 分岐元: -
マージ先: -
製品として出荷可能な状態を常に反映する
develop 分岐元: master
マージ先: master
「次のリリース」のための「最新の開発作業」の変更を反映する

★masterのソースはdevelopブランチなどからマージすることで成長させます。直接masterブランチにてソースコードを修正してはいけないです

  • サポートブランチ

サポートブランチは、作業のため一時的に作られるブランチです。作業としての役目を終えたらブランチ自体を削除します。

feature 分岐元: develop
マージ先: develop
developブランチから派生して、将来的にリリースの視野に入るような機能を開発する。
開発した結果、必要となったらdevelopにマージ、そうでなければ破棄をする
release 分岐元: develop
マージ先: master, develop
開発ブランチでリリースの準備ができたあとで、リリース完了するまでにソースの調整を行う
hotfix 分岐元: master
マージ先: master, develop
「develop作業中でリリース見込みがまだ立てられない、かつ緊急で修正すべき内容がある」といったケースで、本ブランチを生成して修正の作業を行う

登場したブランチを図にしたもの

https://nvie.com/img/git-model@2x.png

実際の作業プロセス

前提

  • githubの使用を想定しているため、github特有の操作を含んでいます。
  • 今回は、「開発工程」、「リリース工程」、この二つのプロセスについて説明します。
  • 具体的に説明するために、審査に提出する工程も含んでいます。

★俺流なところもあるかもですがご了承ください!

開発工程

①開発環境の作成 - 開発用ブランチの作成
 ブランチ:master → develop or develop → feature
 コマンド:

git branch -a // 現在のブランチ、及びリモートブランチ含めた全ブランチを確認する
git checkout -b develop // developブランチの作成(master → develop)
git checkout -b feature_hogehoge // featureブランチの作成(develop → feature)

②作業内容の決定 - "issue"の作成
 githubにてissueを作成する

④開発作業 - "issue"に対して改修の実施
 実施作業:commit, push
 コマンド:

git commit -m "#{issueの番号}" // issueに対して、コミットを紐付ける
git push origin feature_hogehoge  // feature_hogehogeブランチをgithubにプッシュ

⑤レビュー依頼 - pull requestの発行
⑥レビュー作業 - マージ or pull requeseの取り消し

リリース工程

①リリース準備 - リリースブランチの作成
 コマンド:

git branch -a // 現在のブランチ、及びリモートブランチ含めた全ブランチを確認する
git checkout -b release_v1.0.1 // releaseブランチの作成(develop → release)

②審査提出用ファイルの生成 - アーカイブファイルの生成
③(審査で不備がある場合、)修正作業
 修正後コミットを切る

★審査が通るまで、②、③を繰り返す

⑤(審査が通った後、)リリースブランチのマージ
 githubのマージ機能、gitコマンドの"merge", "rebase"など使用する
 →自分のケースだとどれが良いかは、別途整理します。

④(審査が通った後、)ブランチのプッシュ
 プッシュ対象ブランチ:master, develop

⑥リリースタグの作成
 githubで"Draft a new release"を使用し、リリース時点のタグを作成する

おわりに

記事を書いている最中に"Github-flow"という別のgitのブランチ戦略があることを知りました。
一旦は、今回の"git-flow"をベースに開発を進めて、「なんとなくブランチを切る」という開発にさよならしていきたいと思います。