Git

 
カテゴリー Git   タグ

Git

git width=640

git width=640

Git vs centralized source code control systems

A summary of differences

  • GitはSubversionより速い
  • Subversionはリポジトリのサブツリーのみチェックアウトできるが、Gitは履歴を含むリポジトリ全体のクローンを作成する
  • GitのリポジトリはSubversionよりもはるかに小さい
  • Gitは完全分散型で設計されており、開発者はローカルで制御できる
  • GitブランチはSubversionのブランチよりシンプルでリソース負担が少ない
  • Gitブランチはすべての履歴を持つ
  • Gitはブランチおよびマージイベントのより良い監査を提供する
  • Gitのリポジトリファイルは壊れにくく、修復も簡単
  • Subversionはリポジトリのバックアップが簡単(Gitはリポジトリ内のフォルダーを分散可能なため)
  • Gitリポジトリクローンが完全なリポジトリバックアップにできる
  • SubversionのUIはGitより習熟している
  • Subversionは連番のリビジョン番号を使用するので、バージョンのウォークスルーが簡単(GitはSHA-1ハッシュを使う)

Git’s Major Features Over Subversion

  • Distributed Nature
    • ユーザが完全なリポジトリデータのコピーを持つ(Subversionは中央リポジトリしか持たない)
  • Access Control
    • 他のユーザにCommitアクセス権を与える必要がない(いつ誰から何をMergeするか)
  • Branch Handling
    • Subversionではブランチは扱いにくい
    • Gitのブランチはすべてのユーザが日常的に使用するコアコンセプト
  • Performance (Speed of Operation)
    • PushとFetchを除くすべての操作はローカルのため高速
  • Smaller Space Requirements
  • Line Ending Conversion

コメント・シェア

Git公式のPro GitでみるGitアーキテクチャ

 
カテゴリー Git   タグ

Pro Git

Git公式で公開されているPro Git

1.1 Getting Started - About Version Control

Local Version Control Systems

ディレクトリで整理するアプローチは一般的だが、問題も多い。

  • RCS

多くの人々が使っているバージョン管理手法は、他のディレクトリ(気の利いた人であれば、日時のついたディレクトリ)にファイルをコピーするというものです。 このアプローチはとても単純なので非常に一般的ですが、信じられないほど間違いが起こりやすいものです。 どのディレクトリにいるのか忘れやすく、うっかり間違ったファイルに書き込んだり、上書きするつもりのないファイルを上書きしてしまったりします。

Centralized Version Control Systems (CVCs)

中央管理型のバージョン管理システム。

  • CVS、Subversion、Perforce

もし中央データベースのあるハードディスクが破損し、適切なバックアップが保持されていなければ、完全に全てを失ってしまいます。プロジェクトの全ての履歴は失われ、残るのは個人のローカル・マシンにたまたまあった幾らかの単一スナップショット(訳者注:ある時点のファイル、ディレクトリなどの編集対象の状態)ぐらいです。 ローカルVCSシステムも、これと同じ問題があります。つまり、一つの場所にプロジェクトの全体の履歴を持っていると、全てを失うリスクが常にあります。

Distributed Version Control Systems (DVCs)

分散管理型のバージョン管理システム。

  • Git、Mercurial、Bazaar、Darcs

あるサーバーが故障して、DVCSがそのサーバーを介して連携していたとしても、どれでもいいのでクライアント・リポジトリの一つをサーバーにコピーすれば修復できます。 クローンは全て、実際は全データの完全バックアップなのです。

1.3 Getting Started - What is Git

Snapshots, Not Differences

従来のバージョン管理システムはファイルを基本とした変更差分を扱う。

概念的には、他のシステムのほとんどは、情報をファイルを基本とした変更のリストとして格納します。
Git width=640

Gitはコミットの状態をスナップショットとして扱う。このデータ構造の違いがブランチの扱いの違い大きく影響している。

Gitはデータをミニ・ファイルシステムのスナップショットの集合のように考えます。 Gitで全てのコミット(訳注:commitとは変更を記録・保存するGitの操作。詳細は後の章を参照)をするとき、もしくはプロジェクトの状態を保存するとき、Gitは基本的に、その時の全てのファイルの状態のスナップショットを撮り(訳者注:意訳)、そのスナップショットへの参照を格納するのです。 効率化のため、ファイルに変更が無い場合は、Gitはファイルを再格納せず、既に格納してある、以前の同一のファイルへのリンクを格納します。 Gitは、むしろデータを一連のスナップショットのように考えます。
Git width=640

Git Has Integrity

SHAで照合されるのでファイル破損を心配しなくていい。

Gitの全てのものは、格納される前にチェックサムが取られ、その後、そのチェックサムで照合されます。 これは、Gitがそれに関して感知することなしに、あらゆるファイルの内容を変更することが不可能であることを意味します。 この機能は、Gitの最下層に組み込まれ、またGitの哲学に不可欠です。 Gitがそれを感知できない状態で、転送中に情報を失う、もしくは壊れたファイルを取得することはありません。

ハッシュ値ベースの管理

Gitはファイル名ではなく、ファイル内容のハッシュ値によってGitデータベースの中に全てを格納しています。

Git Generally Only Adds Data

コミットした内容を変更するのはめんどくさい。

Gitで行動するとき、ほとんど全てはGitデータベースにデータを追加するだけです。 システムにいかなる方法でも、UNDO不可能なこと、もしくはデータを消させることをさせるのは困難です。 あらゆるVCSと同様に、まだコミットしていない変更は失ったり、台無しにできたりします。

The Three States

ローカル操作する上でこのthe Three Statesのイメージを理解する必要がある。

Gitは、ファイルが帰属する、コミット済、修正済、ステージ済の、三つの主要な状態を持ちます。 コミット済は、ローカル・データベースにデータが安全に格納されていることを意味します。 修正済は、ファイルに変更を加えていますが、データベースにそれがまだコミットされていないことを意味します。 ステージ済は、次のスナップショットのコミットに加えるために、現在のバージョンの修正されたファイルに印をつけている状態を意味します。
このことは、Gitプロジェクト(訳者注:ディレクトリ内)の、Gitディレクトリ、作業ディレクトリ、ステージング・エリアの三つの主要な部分(訳者注:の理解)に導きます。
Git width=640

2.2 Git Basics - Recording Changes to the Repository

Recording Changes to the Repository

Tracked/Untrackedも意識しつつ状態のライフサイクルを理解する。

作業コピー内の各ファイルには追跡されている(tracked)ものと追跡されてない(untracked)ものの二通りがあることを知っておきましょう。 追跡されているファイルとは、直近のスナップショットに存在したファイルのことです。これらのファイルについては変更されていない(unmodified)」「変更されている(modified)」「ステージされている(staged)」の三つの状態があります。 追跡されていないファイルは、そのどれでもありません。直近のスナップショットには存在せず、ステージングエリアにも存在しないファイルのことです。 最初にプロジェクトをクローンした時点では、すべてのファイルは「追跡されている」かつ「変更されていない」状態となります。チェックアウトしただけで何も編集していない状態だからです。
ファイルを編集すると、Git はそれを「変更された」とみなします。直近のコミットの後で変更が加えられたからです。変更されたファイルをステージし、それをコミットする。この繰り返しです。
Git width=640

3.1 Git Branching - Branches in a Nutshell

Branches in a Nutshell

コミットを繰返すとポインターが自動的に進んでいく。

最初にコミットした時点で、直近のコミットを指す master ブランチが作られます。その後コミットを繰り返すたびに、このポインタは自動的に進んでいきます。
Git width=640

masterブランチも他と変わらない。慣習的に意味を持つだけ。

Git の “master” ブランチは、特別なブランチというわけではありません。 その他のブランチと、何ら変わるところのないものです。 ほぼすべてのリポジトリが “master” ブランチを持っているたったひとつの理由は、 git init コマンドがデフォルトで作るブランチが “master” である (そして、ほとんどの人はわざわざそれを変更しようとは思わない) というだけのことです。

HEADは現在の作業ブランチへのポインターを意味している。

Git は、あなたが今どのブランチで作業しているのかをどうやって知るのでしょうか? それを保持する特別なポインタが HEAD と呼ばれるものです。 これは、Subversion や CVS といった他の VCS における HEAD の概念とはかなり違うものであることに注意しましょう。 Git では、HEAD はあなたが作業しているローカルブランチへのポインタとなります。 今回の場合は、あなたはまだ master ブランチにいます。 git branch コマンドは新たにブランチを作成するだけであり、 そのブランチに切り替えるわけではありません。

ブランチの切替で作業ディレクトリのファイルも切り替わる。

気をつけておくべき重要なこととして、Git でブランチを切り替えると、作業ディレクトリのファイルが変更されることを知っておきましょう。 古いブランチに切り替えると、作業ディレクトリ内のファイルは、最後にそのブランチ上でコミットした時点の状態まで戻ってしまいます。 Git がこの処理をうまくできない場合は、ブランチの切り替えができません。

3.2 Git Branching - Basic Branching and Merging

Basic Branching and Merging

マージコミットによってブランチを統合する。

単にブランチのポインタを先に進めるのではなく、Git はこの三方向のマージ結果から新たなスナップショットを作成し、それを指す新しいコミットを自動作成します。 これはマージコミットと呼ばれ、複数の親を持つ特別なコミットとなります。
マージの基点として使用する共通の先祖を Git が自動的に判別するというのが特筆すべき点です。 CVS や Subversion (バージョン 1.5 より前のもの) は、マージの基点となるポイントを自分で見つける必要があります。 これにより、他のシステムに比べて Git のマージが非常に簡単なものとなっているのです。

Git width=640

Git width=640

Basic Merge Conflicts

同じ部分を変更している場合はうまくマージできず、コンフリクトになる。

同じファイルの同じ部分をふたつのブランチで別々に変更してそれをマージしようとすると、Git はそれをうまくマージする方法を見つけられないでしょう。
Git は、標準的なコンフリクトマーカーをファイルに追加するので、ファイルを開いてそれを解決することにします。 コンフリクトが発生したファイルの中には、このような部分が含まれています。

1
2
3
4
5
6
7
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

これは、HEAD (merge コマンドを実行したときにチェックアウトしていたブランチなので、ここでは master となります) の内容が上の部分 (======= の上にある内容)、そして iss53 ブランチの内容が下の部分であるということです。 コンフリクトを解決するには、どちらを採用するかをあなたが判断することになります。 たとえば、ひとつの解決法としてブロック全体を次のように書き換えます。

1
2
3
<div id="footer">
please contact us at email.support@github.com
</div>

このような解決を各部分に対して行い、>>>>> の行をすべて除去します。 そしてすべてのコンフリクトを解決したら、各ファイルに対して git add を実行して解決済みであることを通知します。 ファイルをステージすると、Git はコンフリクトが解決されたと見なします。

補足(Visual Studio Codeのコンフリクト処理)

Visual Studio Codeではコンフリクト状態をどうするか選択の処理が自動挿入される。

VSCode Conflict width=640

3.4 Git Branching - Branching Workflows

Long-Running Branches

慣習的によく使われるdevelopブランチなどのこと。

Git では簡単に三方向のマージができるので、あるブランチから別のブランチへのマージを長期間にわたって繰り返すのも簡単なことです。 つまり、複数のブランチを常にオープンさせておいて、それぞれ開発サイクルにおける別の場面用に使うということもできます。 定期的にブランチ間でのマージを行うことが可能です。

Topic Branches

個別の改修で作成するトピックブランチのこと。

一方、トピックブランチはプロジェクトの規模にかかわらず便利なものです。 トピックブランチとは、短期間だけ使うブランチのことで、何か特定の機能やそれに関連する作業を行うために作成します。 これは、今までの VCS では実現不可能に等しいことでした。 ブランチを作成したりマージしたりという作業が非常に手間のかかることだったからです。 Git では、ブランチを作成して作業をし、マージしてからブランチを削除するという流れを一日に何度も繰り返すことも珍しくありません。

3.5 Git Branching - Remote Branches

Remote Branches

クローンすると自動で origin/master が作成される。master同様 origin に機能的な特別な意味はない。慣習的な物としてはフォークしたプロジェクトのフォーク元として upstream などがある。

リモート参照は、リモートリポジトリにある参照(ポインタ)です。具体的には、ブランチやタグなどを指します。 リモート参照をすべて取得するには、git ls-remote [remote] を実行してみてください。また、git remote show [remote] を実行すれば、リモート参照に加えてその他の情報も取得できます。 とはいえ、リモート参照の用途としてよく知られているのは、やはりリモート追跡ブランチを活用することでしょう。
リモート追跡ブランチは、リモートブランチの状態を保持する参照です。 ローカルに作成される参照ですが、自分で移動することはできません。ネットワーク越しの操作をしたときに自動的に移動します。 リモート追跡ブランチは、前回リモートリポジトリに接続したときにブランチがどの場所を指していたかを示すブックマークのようなものです。
ブランチ名は (remote)/(branch) のようになります。 たとえば、origin サーバーに最後に接続したときの master ブランチの状態を知りたければ origin/master ブランチをチェックします。 誰かほかの人と共同で問題に対応しており、相手が iss53 ブランチにプッシュしたとしましょう。 あなたの手元にはローカルの iss53 ブランチがあります。しかし、サーバー側のブランチは origin/iss53 のコミットを指しています。
Git の “master” ブランチがその他のブランチと何ら変わらないものであるのと同様に、 “origin” もその他のサーバーと何ら変わりはありません。 “master” ブランチがよく使われている理由は、ただ単に git init がデフォルトで作るブランチ名がそうだからというだけのことでした。 同様に “origin” も、git clone を実行するときのデフォルトのリモート名です。 たとえば git clone -o booyah などと実行すると、デフォルトのリモートブランチは booyah/master になります。
手元での作業を同期させるには、git fetch origin コマンドを実行します。 このコマンドは、まず “origin” が指すサーバー (今回の場合は git.ourcompany.com) を探し、まだ手元にないデータをすべて取得し、ローカルデータベースを更新し、origin/master が指す先を最新の位置に変更します。

Pushing

ローカルで作成したブランチはPushでリモートに同期する。

ブランチの内容をみんなと共有したくなったら、書き込み権限を持つどこかのリモートにそれをプッシュしなければなりません。 ローカルブランチの内容が自動的にリモートと同期されることはありません。 共有したいブランチは、明示的にプッシュする必要があります。

Tracking Branches

リモートに紐づいたブランチのこと。

リモート追跡ブランチからローカルブランチにチェックアウトすると、“追跡ブランチ” というブランチが自動的に作成されます(そしてそれが追跡するブランチを`‘上流ブランチ’’といいます)。 追跡ブランチとは、リモートブランチと直接のつながりを持つローカルブランチのことです。 追跡ブランチ上で git pull を実行すると、Git は自動的に取得元のサーバーとブランチを判断します。

Pulling

リモート側の変更を取り込む。

git fetch コマンドは、サーバー上の変更のうち、まだ取得していないものをすべて取り込みます。 しかし、ローカルの作業ディレクトリは書き換えません。 データを取得するだけで、その後のマージは自分でしなければいけません。 git pull コマンドは基本的に、git fetch の実行直後に git merge を実行するのと同じ動きになります。 先ほどのセクションのとおりに追跡ブランチを設定した場合、git pull は、 現在のブランチが追跡しているサーバーとブランチを調べ、そのサーバーからフェッチしたうえで、リモートブランチのマージを試みます。
一般的には、シンプルに fetch と merge を明示したほうがよいでしょう。 git pull は、時に予期せぬ動きをすることがあります。

3.6 Git Branching - Rebasing

Rebasing

リベースでコミットメッセージをきれいにする。

別の方法もあります。 C3 で行った変更のパッチを取得し、それを C4 の先端に適用するのです。 Git では、この作業のことを リベース (rebasing) と呼んでいます。 rebase コマンドを使用すると、一方のブランチにコミットされたすべての変更をもう一方のブランチで再現することができます。
最終的な統合結果には差がありませんが、リベースのほうがよりすっきりした歴史になります。 リベース後のブランチのログを見ると、まるで一直線の歴史のように見えます。 元々平行稼働していたにもかかわらず、それが一連の作業として見えるようになるのです。
リモートブランチ上での自分のコミットをすっきりさせるために、よくこの作業を行います。 たとえば、自分がメンテナンスしているのではないプロジェクトに対して貢献したいと考えている場合などです。 この場合、あるブランチ上で自分の作業を行い、プロジェクトに対してパッチを送る準備ができたらそれを origin/master にリベースすることになります。 そうすれば、メンテナは特に統合作業をしなくても単に fast-forward するだけで済ませられるのです。

The Perils of Rebasing

公開リポジトリにプッシュしたコミットをリベースしてはいけない

Rebase When You Rebase

改変不可派

あなたのリポジトリにおけるコミットの歴史は、実際に発生したできごとの記録 だと見ることもできます。 これは歴史文書であり、それ自体に意味がある。従って、改ざんなど許されないという観点です。 この観点に沿って考えると、コミットの歴史を変更することなどあり得ないでしょう。 実際に起こってしまったことには、ただ黙って 従う べきです。 マージコミットのせいで乱雑になってしまったら? 実際そうなってしまったのだからしょうがない。 その記録は、後世の人々に向けてそのまま残しておくべきでしょう。

履歴整理派

コミットの歴史は、そのプロジェクトがどのように作られてきたのかを表す物語である という考えかたです。 最初の草稿の段階で本を出版したりはしないでしょう。また、自作ソフトウェア用の管理マニュアルであれば、しっかり推敲する必要があります。 この立場に立つと、リベースやブランチフィルタリングを使って、将来の読者にとってわかりやすいように、物語を再編しようという考えに至ります。

中庸派

一般論として、両者のいいとこどりをしたければ、まだプッシュしていないローカルの変更だけをリベースするようにして、 歴史をきれいに保っておきましょう。プッシュ済みの変更は決してリベースしないようにすれば、問題はおきません。

5.1 Distributed Git - Distributed Workflows

Centralized Workflow

リポジトリを共有し、開発者が自分のブランチを作成して平行開発するスタイル。

Git width=640

中央管理型のシステムでは共同作業の方式は一つだけです。それが中央集権型のワークフローです。 これは、中央にある一つのハブ (リポジトリ) がコードを受け入れ、他のメンバー全員がそこに作業内容を同期させるという流れです。 多数の開発者がハブにつながるノードとなり、作業を一か所に集約します。
二人の開発者がハブからのクローンを作成して個々に変更をした場合、最初の開発者がそれをプッシュするのは特に問題なくできます。 もう一人の開発者は、まず最初の開発者の変更をマージしてからサーバーへのプッシュを行い、最初の開発者の変更を消してしまわないようにします。 この考え方は、Git 上でも Subversion (あるいはその他の CVCS) と同様に生かせます。そしてこの方式は Git でも完全に機能します。
また、この例は小規模なチームに限った話ではありません。Git のブランチモデルを用いてひとつのプロジェクト上にたくさんのブランチを作れば、何百人もの開発者が同時並行で作業を進めることだってできるのです。

Integration-Manager Workflow

各開発者がリポジトリを持ち平行開発するスタイル。

Git width=640

Git では複数のリモートリポジトリを持つことができるので、書き込み権限を持つ公開リポジトリを各自が持ち、他のメンバーからは読み込みのみのアクセスを許可するという方式をとることもできます。 この方式には、「公式」プロジェクトを表す公式なリポジトリも含みます。 このプロジェクトの開発に参加するには、まずプロジェクトのクローンを自分用に作成し、変更はそこにプッシュします。 次に、メインプロジェクトのメンテナーに「変更を取り込んでほしい」とお願いします。 メンテナーはあなたのリポジトリをリモートに追加し、変更を取り込んでマージします。そしてその結果をリポジトリにプッシュするのです。

Dictator and Lieutenants Workflow

各開発者がリポジトリを持ち平行開発するスタイルの大規模パターン。

Git width=640

複数リポジトリ型のワークフローのひとつです。 何百人もの開発者が参加するような巨大なプロジェクトで採用されています。有名どころでは Linux カーネルがこの方式です。 統合マネージャーを何人も用意し、それぞれにリポジトリの特定の部分を担当させます。彼らは副官 (lieutenant) と呼ばれます。 そしてすべての副官をまとめる統合マネージャーが「慈悲深い独裁者 (benevalent dictator)」です。 独裁者のリポジトリが基準リポジトリとなり、すべてのメンバーはこれをプルします。

5.2 Distributed Git - Contributing to a Project

Commit Guidelines

コミットメッセージをきれいにする。

コミットメッセージについてのちょっとした注意点をお話しておきましょう。 コミットに関する指針をきちんと定めてそれを守るようにすると、Git での共同作業がよりうまく進むようになります。 Git プロジェクトでは、パッチの投稿用のコミットを作成するときのヒントをまとめたドキュメントを用意しています。Git のソースの中にある Documentation/SubmittingPatches をごらんください。
余計な空白文字を含めてしまわないように注意が必要です。 Git には、余計な空白文字をチェックするための簡単な仕組みがあります。コミットする前に git diff –check を実行してみましょう。おそらく意図したものではないと思われる空白文字を探し、それを教えてくれます。
コミットの単位が論理的に独立した変更となるようにしましょう。 つまり、個々の変更内容を把握しやすくするということです。
すべての変更を同時に追加しさえすれば、一度にコミットしようが五つのコミットに分割しようがブランチの先端は同じ状態になります。あとから変更内容をレビューする他のメンバーのことも考えて、できるだけレビューしやすい状態でコミットするようにしましょう。 こうしておけば、あとからその変更の一部だけを取り消したりするのにも便利です。
最後に注意しておきたいのが、コミットメッセージです。 よりよいコミットメッセージを書く習慣を身に着けておくと、Git を使った共同作業をより簡単に行えるようになります。 一般的な規則として、メッセージの最初には変更の概要を一行 (50 文字以内) にまとめた説明をつけるようにします。その後に空行をひとつ置いてからより詳しい説明を続けます。 Git プロジェクトでは、その変更の動機やこれまでの実装との違いなどのできるだけ詳しい説明をつけることを推奨しています。
メッセージでは命令形、現在形を使うようにしています。 つまり “私は○○のテストを追加しました (I added tests for)” とか “○○のテストを追加します (Adding tests for,)” ではなく “○○のテストを追加 (Add tests for.)” 形式にするということです。 Tim Pope が書いたテンプレート (の日本語訳) を以下に示します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
短い (50 文字以下での) 変更内容のまとめ

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

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

- 箇条書きも可能

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

Forked Public Project

フォークの作法。

まずはメインリポジトリをクローンしましょう。そしてパッチ用のトピックブランチを作り、そこで作業を進めます。 このような流れになります。
rebase -i を使ってすべての作業をひとつのコミットにまとめたり、メンテナがレビューしやすいようにコミット内容を整理したりといったことも行うかもしれません。
ブランチでの作業を終えてメンテナに渡せる状態になったら、プロジェクトのページに行って “Fork” ボタンを押し、自分用に書き込み可能なフォークを作成します。 このリポジトリの URL を追加のリモートとして設定しなければなりません。ここでは myfork という名前にしました。
今後、自分の作業内容はここにプッシュすることになります。 変更を master ブランチにマージしてからそれをプッシュするよりも、今作業中の内容をそのままトピックブランチにプッシュするほうが簡単でしょう。 もしその変更が受け入れられなかったり一部だけが取り込まれたりした場合に、master ブランチを巻き戻す必要がなくなるからです。メンテナがあなたの作業をマージするかリベースするかあるいは一部だけ取り込むか、いずれにせよあなたはその結果をリポジトリから再度取り込むことになります。
自分用のフォークに作業内容をプッシュし終えたら、それをメンテナに伝えましょう。 これは、よく「プルリクエスト」と呼ばれるもので、ウェブサイトから実行する (GutHub には Pull request を行う独自の仕組みがあります。詳しくは GitHub で説明します) こともできれば、 git request-pull コマンドの出力をプロジェクトのメンテナにメールで送ることもできます。
自分がメンテナになっていないプロジェクトで作業をする場合は、master ブランチでは常に origin/master を追いかけるようにし、自分の作業はトピックブランチで進めていくほうが楽です。そうすれば、パッチが拒否されたときも簡単にそれを捨てることができます。 また、作業内容ごとにトピックブランチを分離しておけば、本流のリポジトリが更新されてパッチがうまく適用できなくなったとしても簡単にリベースできるようになります。

コメント・シェア

Hexoの記事に目次をつける

 
カテゴリー SSG   タグ

hexo-toc

hexo-tocプラグインを使用する。

Install

npm install hexo-toc --save

Configuration

TOCを有効にする

_config.ymlに以下を追記する。

1
2
3
4
5
6
7
8
9
toc:
maxdepth: 3
class: toc
slugify: transliteration
decodeEntities: false
anchor:
position: after
symbol: '#'
style: header-anchor

Page configuration

目次をおきたい位置に`

目次

  1. hexo-toc
  2. Install
  3. Configuration
  4. Page configuration

`を記述する。

目次サンプル

コメント・シェア

HexoでGitHub flavored markdownを使う

 
カテゴリー Markdown SSG   タグ

hexo-renderer-marked

Install

npm install hexo-renderer-marked --save

Configuration

GitHub flavored markdown(gfm) を有効にする

_config.ymlに以下を追記

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
marked:
gfm: true
pedantic: false
breaks: true
smartLists: true
smartypants: true
modifyAnchors: 0
autolink: true
sanitizeUrl: false
headerIds: true
prependRoot: false
external_link:
enable: false
exclude: []
nofollow: false

GitHub flavored markdown

gfm - gfm task list items

  • foo
  • bar
  • foo
    • bar
    • baz
  • bim

breaks - gfm line breaks

効いていない……

1
2
Hello  (<-- two spaces)
World

Hello
World

1
2
Hello (<-- one spaces)
World

Hello
World

1
2
Hello (<-- no spaces)
World

Hello
World

autolink

1
https://hexo.io

https://hexo.io

Definition/Description Lists

1
2
3
4
5
6
Definition Term
: This is the definition for the term

Definition Term
: Definition 1
: Definition 2
Definition Term
This is the definition for the term
Definition Term
: Definition 1
Definition 2

コメント・シェア

Python loggingによるログ操作

 
カテゴリー Python   タグ

LogLevelをどう設定すべきか

行いたいタスク そのタスクに最適なツール
通常の操作中に発生したイベント logging.info()
診断のための詳細な出力 logging.debug()
特定のランタイムイベントに関わる警告(呼び出し側を修正すべき) warnings.warn()
特定のランタイムイベントに関わる警告 logging.warning()
特定のランタイムイベントに関わるエラー raise exception
例外の送出をしないエラーの抑制 logging.error(), logging.exception(), logging.ciritical()

getLogger()

getLogger()で一度生成されたloggerは同一プロセス内では1つの実体として動作している。loggingクックブック内ではモジュールのグローバル変数としてloggerを定義している。

logging.getLogger(‘someLogger’)の複数回の呼び出しは同じloggerへの参照を返します。これは同じPythonインタプリタプロセス上で動いている限り、一つのモジュールの中からに限らず、モジュールをまたいでも当てはまります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import logging

# create logger
module_logger = logging.getLogger('spam_application.auxiliary')

class Auxiliary:
def __init__(self):
self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary')
self.logger.info('creating an instance of Auxiliary')

def do_something(self):
self.logger.info('doing something')
a = 1 + 1
self.logger.info('done doing something')

def some_function():
module_logger.info('received a call to "some_function"')

disable_existing_loggersでloggerが無効化される

logging.config.dictConfigで設定を読み込んくとすでに作成済のloggerが無効化されてしまう。無効化させないためにはdisable_existing_loggersFalseに設定する。

disable_existing_loggers.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import logging
import logging.config

logger = logging.getLogger(__name__)

# load config from file
# logging.config.fileConfig('logging.ini', disable_existing_loggers=False)
# or, for dictConfig
logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': False, # this fixes the problem
'formatters': {
'standard': {
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
},
},
'handlers': {
'default': {
'level':'INFO',
'class':'logging.StreamHandler',
'formatter':'standard'
},
},
'loggers': {
'': {
'handlers': ['default'],
'level': 'INFO',
'propagate': True
}
}
})

logger.debug('Debug log message')
logger.info('Info log message')
logger.warning('Warning log message')
logger.error('Error log message')

disable_existing_loggersがTrueの場合

ログが出力されない。

1
$python disable_existing_loggers.py

disable_existing_loggersがFalseの場合

期待通りのログが出力される。

1
2
3
4
$python disable_existing_loggers.py
2020-04-22 13:54:22,207 [INFO] __main__: Info log message
2020-04-22 13:54:22,209 [WARNING] __main__: Warning log message
2020-04-22 13:54:22,209 [ERROR] __main__: Error log message

loggerとdisable_existing_loggersの挙動をみる

logging_treeモジュール

loggerをツリー構造で見やすく表示する、logging_treeを使う。pip install logging_treeでインストールしておく。

my_module.py

テスト用のClassとFunctionでいくつかのLogLevelのメッセージを表示するモジュール。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import logging

def foo():
logger = logging.getLogger(__name__)
logger.debug('Debug log message/function')
logger.info('Info log message/function')
logger.warning('Warning log message/function')
logger.error('Error log message/function')

class Bar(object):
def __init__(self, logger=None):
self.logger = logger or logging.getLogger(__name__)

def bar(self):
self.logger.debug('Debug log message/method')
self.logger.info('Info log message/method')
self.logger.warning('Warning log message/method')
self.logger.error('Error log message/method')

main.py

テスト用のモジュールでログ出力とloggerのツリー構造を確認する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import logging
import logging.config
import logging_tree

# load my module
import my_module

print("--------------------------------------------------------")
print("Step1: 標準のroot logger")
logging_tree.printout()
print("--------------------------------------------------------")

print("--------------------------------------------------------")
print("Step2: なにも設定せずgetLogger()を呼ぶ")
my_module.foo()
bar = my_module.Bar()
bar.bar()
print("")
print("getLogger()によってmy_moduleというloggerが生成されている")
logging_tree.printout()
print("--------------------------------------------------------")

print("--------------------------------------------------------")
print("Step3: logging.ini / disable_existing_loggers=True")
logging.config.fileConfig('logging.ini', disable_existing_loggers=True)
my_module.foo()
bar = my_module.Bar()
bar.bar()
print("")
print("すでにStep1でmy_module loggerは作成済だったので、無効化されている")
logging_tree.printout()
print("--------------------------------------------------------")

print("--------------------------------------------------------")
print("Step4: logging.ini / disable_existing_loggers=False")
logging.config.fileConfig('logging.ini', disable_existing_loggers=False)
my_module.foo()
bar = my_module.Bar()
bar.bar()
print("")
print("disable_existing_loggers=Falseで有効化されている")
logging_tree.printout()
print("--------------------------------------------------------")

logging.ini

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[loggers]
keys=root

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

main.py実行結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
$python main.py
--------------------------------------------------------
Step1: 標準のroot logger
<--""
Level WARNING
--------------------------------------------------------
--------------------------------------------------------
Step2: なにも設定せずgetLogger()を呼ぶ
Warning log message/function
Error log message/function
Warning log message/method
Error log message/method

getLogger()によってmy_moduleというloggerが生成されている
<--""
Level WARNING
|
o<--"my_module"
Level NOTSET so inherits level WARNING
--------------------------------------------------------
--------------------------------------------------------
Step3: logging.ini / disable_existing_loggers=True

すでにStep1でmy_module loggerは作成済だったので、無効化されている
<--""
Level DEBUG
Handler Stream <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
Level DEBUG
Formatter fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s' datefmt=''
|
o<--"my_module"
Level NOTSET so inherits level DEBUG
Disabled
--------------------------------------------------------
--------------------------------------------------------
Step4: logging.ini / disable_existing_loggers=False
2020-04-04 22:03:42,281 - my_module - DEBUG - Debug log message/function
2020-04-04 22:03:42,281 - my_module - INFO - Info log message/function
2020-04-04 22:03:42,281 - my_module - WARNING - Warning log message/function
2020-04-04 22:03:42,281 - my_module - ERROR - Error log message/function
2020-04-04 22:03:42,281 - my_module - DEBUG - Debug log message/method
2020-04-04 22:03:42,281 - my_module - INFO - Info log message/method
2020-04-04 22:03:42,281 - my_module - WARNING - Warning log message/method
2020-04-04 22:03:42,281 - my_module - ERROR - Error log message/method

disable_existing_loggers=Falseで有効化されている
<--""
Level DEBUG
Handler Stream <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
Level DEBUG
Formatter fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s' datefmt=''
|
o<--"my_module"
Level NOTSET so inherits level DEBUG
--------------------------------------------------------

Pythonの例外処理とトレースバック

Pythonの例外処理をCatchして、ログ出力する。StuckTraceは改行を含む複数行の内容になるので、JSON形式でのログ出力を行う。JSON形式でログ出力するために、jsonloggerを使うのでpip install python-json-loggerでインストールする。

複数行の例外は読みやすいですが、外部のログサービスを使用してログを集計している場合は、ログをJSONに変換して、複数行のログが正しく解析されるようにする必要があります。

lowermodule.py

  • 例外をキャッチしてスタックトレースをログに記録する
  • スタックトレースは複数行になるので、JSON形式で扱いやすく出力する
  • JSONにはカスタム項目(extra=)を追記することも可能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# lowermodule.py
import logging.config
import traceback
import time
from pythonjsonlogger import jsonlogger
import logging_tree

def word_count(myfile):
#logger = logging.getLogger(__name__)
logger = logging.getLogger('lowermodule')
logging.config.fileConfig('logging.json.ini', disable_existing_loggers=False)
print(logger.name)
logging_tree.printout()
try:
starttime = time.time()
with open(myfile, 'r') as f:
file_data = f.read()
words = file_data.split(" ")
final_word_count = len(words)
endtime = time.time()
duration = endtime - starttime
logger.info("this file has %d words", final_word_count, extra={"run_duration":duration})
return final_word_count
except OSError as e:
logger.error(e, exc_info=True)
except:
logger.error("uncaught exception: %s", traceback.format_exc())
return False

if __name__ == '__main__':
word_count('myfile.txt')

logging.json.ini

__name__lowermoduleの場合にconsoleとjsonに出力する。consoleはroot loggerの定義によって、jsonはlowermodule loggerの定義によって出力される。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[loggers]
keys=root,lowermodule

[handlers]
keys=consoleHandler,fileHandler

[formatters]
keys=simpleFormatter,json

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_lowermodule]
level=DEBUG
handlers=fileHandler
qualname=lowermodule

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=json
args=("myapp.log",)

[formatter_json]
class=pythonjsonlogger.jsonlogger.JsonFormatter
format=%(asctime)s %(name)s %(levelname)s %(message)s

[formatter_simpleFormatter]
format=%(asctime)s %(name)s - %(levelname)s:%(message)s

lowermodule.py実行結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$python lowermodule.py
lowermodule
<--""
Level DEBUG
Handler Stream <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
Level DEBUG
Formatter fmt='%(asctime)s %(name)s - %(levelname)s:%(message)s' datefmt=None
|
o<--"lowermodule"
Level DEBUG
Handler File '/work/logging_traceback/myapp.log'
Level DEBUG
Formatter <pythonjsonlogger.jsonlogger.JsonFormatter object at 0x7f41b0c0e040>
2020-04-05 01:12:37,312 lowermodule - ERROR:[Errno 2] No such file or directory: 'myfile.txt'
Traceback (most recent call last):
File "lowermodule.py", line 16, in word_count
with open(myfile, 'r') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'myfile.txt'

$cat myapp.log
{"asctime": "2020-04-05 01:12:37,312", "name": "lowermodule", "levelname": "ERROR", "message": "[Errno 2] No such file or directory: 'myfile.txt'", "exc_info": "Traceback (most recent call last):\n File \"lowermodule.py\", line 16, in word_count\n with open(myfile, 'r') as f:\nFileNotFoundError: [Errno 2] No such file or directory: 'myfile.txt'"}

コメント・シェア

GitHubチュートリアル

 
カテゴリー Git Markdown SSG Tutorial   タグ

GitHub Guides

GitHub公式のチュートリアル。シンプルにまとまっている。

Hello World (ブランチ作成~Pull Request~Merge)

Web UIを使ったブランチ作成 ~ Pull Request ~ Merge操作。
masterからBranch ofしてPull Request ~ Mergeする、簡単なGitHub flowプロセスチュートリアル。ブランチの仕組みを理解してもらうのに良いチュートリアル。

Step 1. Create a Repository

リポジトリを作成する。

Step 2. Create a Branch

リポジトリの画面でbranch: masterからSwitch branch/tagsを選択して、readme-editsをいれてCreate branchをクリックして作成。

  • デフォルトでは、masterがあり、これがもっとも信頼できるブランチ
  • ブランチを使用して、masterへコミットする前にテストを行う

Step 3. Make and commit changes

README.mdを画面上から修正。Commitコメントなども記入。Commit先がreadme-editsになっていることを確認したうえで、Commit change

Step 4. Open a Pull Request

pull requestsタブでNew pull request
base: mastercompare: readme-editsにするとAble to merge. These branches can be automatically merged.が表示される。

併せて表示されたCreate pull requestをクリック。表示された画面で、pull requestのtitleやメッセージを記入した上で、Create pull requestをクリック。

Step 5. Merge your Pull Request

pull requestsタブでにStep4で作成したPull Requestが表示されている。

画面下部からチャットメッセージを投稿することができる。

リクエストを承認するならMerge pull requestをクリックしてマージする。

マージした後はPull request successfully merged and closedという内容が表示されているので、Delete branchでブランチを削除する。

Forking Projects (Fork~Pull Request)

リポジトリをForkしてPull Requestまでの操作を行うチュートリアル
細かい操作の説明はないので、Git操作は知っている前提になっている。

Step1. Fork the repository

Spoon-Knifeリポジトリの右上にあるForkボタンを押してプロジェクトをフォークする。

Forking octocat/Spoon-Knifeというメッセージの画面で少し待つとリポジトリのフォークが完成する。

Step2. Clone your fork

フォークしたプロジェクトをローカルにクローンする。

  • originhttps://www.github.com/<your_username>/Spoon-Knife
  • upstreamをオリジナルのSpoon-Knifeにする。

Step3. Making a Pull Request

ローカルでindex.htmlファイルを編集してpushする。

  • stage: git addで追加する
  • local repository: git commitでcommitする。
  • remote repository: git pushでpushする。

Step4. Making a Pull Request

https://www.github.com/<your_username>/Spoon-Knifepull requestsタブでNew pull request

base repository: octcat/Spoon-Knife:base:masterhead repository: <your_username>/Spoon-Knife:compare masterにするとAble to merge. These branches can be automatically merged.が表示される。

併せて表示されたCreate pull requestをクリック。表示された画面で、pull requestのtitleやメッセージを記入した上で、Create pull requestをクリック。

Mastering Issues

GitHub Flavored Markdownのチュートリアル。

Mastering Markdown (GitHub Flavored Markdown)

Syntax highlighting

1
2
3
4
5
function fancyAlert(arg) {
if(arg) {
$.facebox({div:'#foo'})
}
}

Task Lists

1
2
3
4
- [x] @mentions, #refs, [links](), **formatting**, and <del>tags</del> supported
- [x] list syntax required (any unordered or ordered list supported)
- [x] this is a complete item
- [ ] this is an incomplete item
  • @mentions, #refs, links, formatting, and tags supported
  • list syntax required (any unordered or ordered list supported)
  • this is a complete item
  • this is an incomplete item

Tables

1
2
3
4
First Header | Second Header
------------ | -------------
Content from cell 1 | Content from cell 2
Content in the first column | Content in the second column
First Header Second Header
Content from cell 1 Content from cell 2
Content in the first column Content in the second column

Getting Started with GitHub Pages

GitHub Pagesのチュートリアル。

Step1. Create Your Website

username.github.ioという名前のリポジトリを作成。usernameはGitHubのアカウント。

GitHub Pages width=640

Settings -> GitHub PagesChose themeからテーマを選択。

GitHub Pages width=640

GitHub Pages width=640

Jeykllで静的ページを作成するため、元になるindex.mdファイルを作成。

GitHub Pages width=640

編集したら、Commitコメントを入れて Commit changes

GitHub Pages width=640

username.github.ioにアクセスするとページが表示される。

GitHub Pages width=640

Step2. Making Changes

自動生成されている_config.ymlを編集してページを更新する。

GitHub Pages width=640

テーマ選択だけが設定されている。

GitHub Pages width=640

titledescriptionを追記。

GitHub Pages width=640

ページが更新される。

GitHub Pages width=640

Step3. リポジトリ毎のページ

リポジトリ用のページusername.github.io/<reponame>でアクセスできる。作成方法は同じ。

GitHub Pages width=640

Settings -> GitHub Pagessourceからmaster branchを選択。

GitHub Pages width=640

GitHub Pages width=640

Jeykllで静的ページを作成するため、元になるindex.mdファイルを作成。

GitHub Pages width=640

GitHub Pages width=640

Settings -> GitHub PagesChose themeからテーマを選択。

GitHub Pages width=640

テーマを選択。

GitHub Pages width=640

コメント・シェア

GitできれいなPull Requestを送る

 
カテゴリー Git   タグ

How to write the perfect pull request

Approach to writing a Pull Requestの要約

  • Pull Requestの目的を含める
  • 作業が行われている理由の概要(経緯に精通していることを求めない)
  • 誰もがこのPull Requestを読んでいる可能性があることを忘れない
  • 必要なフィードバックがある場合はそれについて明確に説明
  • Pull Requestが進行中の場合はフィードバックが必要な時期を明記し[WIP]などのタイトル接頭辞を付ける
  • ディスカッションに参加させたい@メンションとその理由を記載
    • 例)/cc @GitHub/security、このアプローチに関する懸念は?

Offering feedbackの要約

  • 問題の文脈とこのPull Requestが存在する理由をよく理解する
  • 同意できない場合、応答する前に数分検討してから
  • Ask, dont’ tell. (“できない”より”なんでそれをするの?”)
  • コードを変更する理由を説明
  • コードを簡略化または改善する方法を提供
  • 中傷的な用語を使用しない
  • 謙虚になる
  • 誇張を避ける
  • グループの批評を通じて、専門的なスキル、グループの知識、製品の品質向上を目指す
  • オンラインコミュニケーションのマイナスバイアスに注意
  • 絵文字を使用してトーンを明確にする

Responding to feedbackの要約

  • 説明を求める
  • 問題解決のために行った決定を説明する
  • すべてのコメントに返信する
  • Followup Commit、またはPull Requestへのリンク
  • 議論が混乱している場合、オフラインで議論し、まとめたフォローアップを投稿することも検討

Pull Request Hell

The Right Way / Being the Creatorの要約

  • Keep an open mind: 建設的な批評の必要がある、そしてそれがPRのすべて
  • Stay focused on your goal: 目的に集中し、大きなリファクタリングをしない
  • Document non trivial lines of code: 重要なコードにドキュメントを
  • Write unit tests for all your changes: PRとともにテストコードを
  • Finally read your code: 最後にコードを読んで簡素化・改善を行う

The Right Way / Being the Approverの要約

  • Make time to review the code: コードを確認する時間を確保
  • Write your own notes before using the tool: ツールを使う前にメモで考えを整理する
  • Make sure you know your standards: 自分の基準を知る
  • Learning, I think this is the most important part of being an approver: 学ぶことがもっとも重要

The Wrong Wayの要約

  • Writing comments just to write comments: コメントを書くためだけのコメント
  • Not learning: 学ばない
  • Creating a backdoor: 自分のコードを承認するバックドアを作る
  • Constantly commenting on Syntax and Styling: コーディング規約コメントばかりしている

10 tips for better Pull Requests

10 tips for better Pull Requestsの要約

  1. Make it small: 小さく焦点を絞ったPull Request/1ダース以下のファイル変更なら悪くない
  2. Do only one thing: 1つのPull Requestは1つのテーマのみ扱う、or Welcome to Merge Hell
  3. Watch your line width: レビュアーがdiffしやすいように
  4. Avoid re-formatting: フォーマットを変更したければ別Pull Requestで
  5. Make sure the code builds: 最低でも動くものを
  6. Make sure all tests pass: 最低でも自動テストをパスするものを
  7. Add tests: テストの追加も
  8. Document your reasoning: 理由を書く
    • 「何を」書いたのかではなく、「なぜ」その方法でコードを書いたのかを説明
  9. Write well: 正しく作文する
  10. Avoid thrashing: スラッシング(無意味なコミット履歴)を避ける

Document your reasoningの要約

  1. Self-documenting code: 自己文書化したコード
  2. Code comments: うまく自己文書化できなかったらコメントで
  3. Commit messages: コードに書くことがふさわしくない内容を
  4. Pull Request comments: 自己文書化したコード

コメント・シェア

Google AdSense

Google AdSenseにサイトを登録する

google-adsense width=640

審査を受ける(失敗した例)

指定されたAdSenseコードをサイトに貼り付けて閲覧可能にする

google-adsense width=640

google-adsense width=640

サイトの修正

google-adsense width=640

コンテンツが存在しないはページがクロールされていないため。Google Search ConsoleでGoogleのクロールが完了してインデックス化されたことを確認したうえで再登録を実施する。
また、必須コンテンツとしてプライバシーポリシーの掲載が求められているので、プライバシーポリシーページを作成。

  • Google Search Consoleに登録し、Search Consoleのカバレッジが表示されるまで待つ
  • プライバシーポリシーを作成しサイトから閲覧できるようにする

再審査を受ける

google-adsense width=640

サイトを審査できません
新型コロナウイルス感染症 (COVID-19) の世界的流行の影響で、Google では現在、一部のサービスで一時的に遅延が発生しています。そのため、現時点ではお客様のサイトを審査することができません。

COVID19の影響がここまで……

審査合格

なんども同じエラーを繰り返し、6月にようやく審査完了。

google-adsense complete width=640

google-adsense complete width=640

google-adsense complete width=640

google-adsense complete width=640

google-adsense complete width=640

ads.txt

google-adsense complete width=640

ads.txtをダウンロードしてドメインのルートディレクトリに配置。警告メッセージはすぐには消えないが、ads.txt配置後しばらくすると消える。

自動広告の有効化

Google Adsense用のタグが表示されるので、サイトに貼り付ける。
内容は審査時のものと同じ。

google-adsense complete width=640

自動広告を有効化する。
サマリーのペンシルマークからサイトの広告設定が可能。

google-adsense complete width=640

google-adsense complete width=640

google-adsense complete width=640

コメント・シェア

Google Analytics

Google Analyticsにサイトを登録する

サイトを登録する

google-analytics width=640

今回はWebサイトなので、ウェブを選択。

google-analytics width=640

サイトのURLを設定。

google-analytics width=640

利用規約に同意して登録完了。

google-analytics width=640

トラッキングコードを取得する

管理 -> トラッキング情報からサイトに埋め込むトラッキングコードを確認する。

google-analytics width=640

google-analytics width=640

サイトのアクセス状況を把握する

情報が収集されると、ホーム画面でトラフィック状況を確認できる。

google-analytics width=640

ロケール別の統計。

google-analytics width=640

国別の統計。

google-analytics width=640

ブラウザ別の統計。

google-analytics width=640

OS別の統計。

google-analytics width=640

コメント・シェア



nullpo

めも


募集中


Japan