SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

サポートエンジニアが解説するGitHub

Pull Requestで日本語が文字化けしたときの対処方法

サポートエンジニアが解説するGitHub 第1回

文字化けを防ぐには

 したがって、そのファイルのプログラミング言語を予め指定し、シンタックスハイライトを有効化できれば、文字化けを回避できる可能性が高いということになります。UTF-8以外のエンコーディングを使って開発を行う場合で、かつ、プログラミング言語の判定ができない可能性のある拡張子を持ったファイルを扱う場合は、この方法を試してみてください。GitHubに対してプログラミング言語の指定をする方法は2つあるので、それぞれ紹介します。

.gitattributesを使ってファイルの言語を指定する

 .gitattributesとは、Gitの属性を細かくコントロールするためのファイルです。.gitattributesというファイルに

*.src linguist-language=JavaScript

 と記載することで、全ての.srcという拡張子を持つファイルをJavaScriptファイルとして認識させた上で、日本語に変更を加えたコミット387fd5fでは、文字化けは起きていません。

modelineを使ってファイルの言語を指定する

 もう一つの方法は、ファイル内にVimもしくはEmacs形式のmodelineを記入する方法です。各ファイルの最後にmodelineを追記し、同じくファイルをJavaScriptとして認識させた上で、日本語に変更を加えたコミット62c5379でも、やはり文字化けは起きていません。

 どちらの方法でも、6つ全てのファイルでシンタックスハイライトが有効になっていることがわかります。

シンタックスハイライトが有効になっている
シンタックスハイライトが有効になっている

 また、.gitattributesでは、ファイルごと、ディレクトリ以下のすべてのファイル、特定の拡張子をもったすべてのファイル、など細かい指定が可能です。詳細はLinguistのREADMEのOverridesセクションを参照してください。

Linguistの仕組み

 最後にこのプログラミング言語判定ライブラリLinguistの仕組みを簡単に解説します。

 前述したように、LinguistはGitHubの言語バーを実装するのに使われているライブラリです。GitHubはこのライブラリをオープンソースプロジェクトとして公開しているので、誰でもコードを読むことができます。

 言語の判定には、その名の通りdetectというメソッドが起点になります。detectメソッドは入力(Blob)に対して複数のストラテジーを順に評価しながら候補を絞り込んでいき、最も可能性が高いものを返すような仕組みになっています。

 ストラテジーは下記の6つです(linguist.rb#L60-L67)。

  STRATEGIES = [
    Linguist::Strategy::Modeline,
    Linguist::Strategy::Filename,
    Linguist::Shebang,
    Linguist::Strategy::Extension,
    Linguist::Heuristics,
    Linguist::Classifier
  ]

 ご覧の通り、上記で説明したmodelineの追加は、Modelineストラテジーによって一番最初に評価されます。ここでマッチすれば、その後のストラテジーは評価されません。その次にファイル名、ファイルのシェバン、拡張子をそれぞれ評価するストラテジーが実行されます。

 ファイル名や拡張子の一覧はlanguages.ymlというファイルに記載されています。今回の例で使用した.srcという拡張子はこのファイルに存在しません。つまり、Extensionストラテジーにはマッチしないということです。

 Heuristicsストラテジーは経験則的な判定方法です。例えば.sqlというSQLファイルはさまざまな種類のデータベースで利用されています。そのようなケースでは、最初の4つのストラテジーだけでは、そのファイルがPostgreSQLのSQL文なのか、IBM Db2のものか、またはOracleのものなのか、正確に判定できません。そのようなケースで、データベースごとのSQLファイルの特徴を元に判断を行うのがこのストラテジーです。.sqlの場合は以下のように記述されています(heuristics.rb#L453-L467)。

disambiguate ".sql" do |data|
  if /^\\i\b|AS \$\$|LANGUAGE '?plpgsql'?/i.match(data) || /SECURITY (DEFINER|INVOKER)/i.match(data) || /BEGIN( WORK| TRANSACTION)?;/i.match(data)
	#Postgres
	Language["PLpgSQL"]
  elsif /(alter module)|(language sql)|(begin( NOT)+ atomic)/i.match(data)  || /signal SQLSTATE '[0-9]+'/i.match(data)
	#IBM db2
	Language["SQLPL"]
  elsif /\$\$PLSQL_|XMLTYPE|sysdate|systimestamp|\.nextval|connect by|AUTHID (DEFINER|CURRENT_USER)/i.match(data) || /constructor\W+function/i.match(data)
	#Oracle
	Language["PLSQL"]
  elsif ! /begin|boolean|package|exception/i.match(data)
	#Generic SQL
	Language["SQL"]
  end
end

 Classifierは、それでも言語が判定できなかった場合に使われる最後のストラテジーで、単純ベイズ分類器の手法を使ってテキストファイルの言語を推測します。各言語の訓練データはsamplesディレクトリに保存されています。

 もちろん、これら6つのストラテジーを用いても言語が判定できない場合もあります。今回のように、内容がJavaScriptで拡張子が.srcというファイルは、ここまでの6つのストラテジーを使ってもJavaScriptと判定されることはありませんでした。

 Linguistはローカルで実行して確認できるので、試してみましょう。lowply/garbled-diff-testリポジトリをクローンし、下記のコマンドを実行してください。

$ bundle install

# (...Install RubyGems...)

$ bundle exec linguist example-for-linguist.src

 結果は下記のようになるはずです。

example-for-linguist.src: 13 lines (11 sloc)
  type:      Text
  mime type: application/x-wais-source
  language:

 languageの値が空になっていて、example-for-linguist.srcの言語が判定できなかったことがわかります。ただし、Classifierストラテジーはファイルの内容を元に判定を行うので、同じように「内容はJavaScriptだが拡張子は.src」というファイルであっても、内容次第ではJavaScriptと判定される可能性もあります。

まとめ

 本稿では、GitHubが日本語などのマルチバイト文字をどのように扱っているのかというトピックを、文字化けというキーワードを軸に、GitHubのサポートエンジニアが解説しました。なお、本稿に記載の内容は2018年8月時点の仕様を元にしています。GitHubは常にアップデートされており、今後エンコーディングにまつわる仕様も変わる可能性があります。

 それでは、次回は以降の連載もお楽しみに!

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
サポートエンジニアが解説するGitHub連載記事一覧
この記事の著者

水谷 翔(GitHub, Inc.)(ミズタニ ショウ)

 東京都生まれ。工学部建築学科出身。ウェブデザイナー、インフラエンジニア、AWSのデータセンターテクニシャン等のキャリアを経て2016年6月にGitHub, Inc.に入社。Enterprise Support Engineerとして、GitHubの企業向け製品GitHub Enterpriseを導入してい...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/11079 2018/09/20 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー