Git
English ▾ トピック ▾ 最新バージョン ▾ gitprotocol-http 最終更新日 2.44.0

名前

gitprotocol-http - Git HTTP ベースのプロトコル

概要

<over-the-wire-protocol>

説明

Git は、HTTP ベースの 2 つの転送プロトコルをサポートしています。接続のサーバー側で標準の HTTP サーバーのみを必要とする「ダム」プロトコルと、Git 対応の CGI(またはサーバーモジュール)を必要とする「スマート」プロトコルです。このドキュメントでは、両方のプロトコルについて説明します。

設計機能として、スマートクライアントは「ダム」プロトコルの URL をスマート URL に自動的にアップグレードできます。これにより、すべてのユーザーが同じ公開 URL を持つことができ、ピアは自動的に利用可能な最も効率的な転送を選択します。

URL 形式

HTTP でアクセスされる Git リポジトリの URL は、RFC 1738 で規定されている標準の HTTP URL 構文を使用するため、次の形式になります。

http://<host>:<port>/<path>?<searchpart>

このドキュメントでは、プレースホルダー `$GIT_URL` は、エンドユーザーが入力した http:// リポジトリ URL を表します。

サーバーは、`$GIT_URL` と一致する場所にアクセスするすべての要求を処理する必要があります。これは、Git で使用される「スマート」と「ダム」の両方の HTTP プロトコルは、ユーザーが提供した `$GIT_URL` 文字列の末尾に追加のパスコンポーネントを追加することによって動作するためです。

ルーズオブジェクトを要求するダムクライアントの例

$GIT_URL:     http://example.com:8080/git/repo.git
URL request:  http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355

キャッチオールゲートウェイへのスマートリクエストの例

$GIT_URL:     http://example.com/daemon.cgi?svc=git&q=
URL request:  http://example.com/daemon.cgi?svc=git&q=/info/refs&service=git-receive-pack

サブモジュールへのリクエストの例

$GIT_URL:     http://example.com/git/repo.git/path/submodule.git
URL request:  http://example.com/git/repo.git/path/submodule.git/info/refs

クライアントは、ユーザーが提供した `$GIT_URL` 文字列に末尾の `/` がある場合は削除する必要があります。これにより、空のパストークン(`//`)がサーバーに送信される URL に表示されるのを防ぎます。互換性のあるクライアントは、`$GIT_URL/info/refs` を `foo/info/refs` として展開する必要があり、`foo//info/refs` としては展開しないでください。

認証

リポジトリへのアクセスに認証が必要な場合は、標準の HTTP 認証が使用され、HTTP サーバーソフトウェアによって設定および適用される場合があります。

Git リポジトリは標準のパスコンポーネントによってアクセスされるため、HTTP サーバー内のディレクトリベースの権限を使用して、リポジトリへのアクセスを制御できます。

クライアントは、RFC 2617 で説明されている基本認証をサポートする必要があります。サーバーは、Git サーバーソフトウェアの前に配置された HTTP サーバーに依存することによって、基本認証をサポートする必要があります。

サーバーは、認証またはアクセス制御の目的で HTTP クッキーを要求しないでください。

クライアントとサーバーは、ダイジェスト認証などの他の一般的な HTTP ベースの認証形式をサポートできます。

SSL

クライアントとサーバーは、特に基本 HTTP 認証に依存する場合のパスワードを保護するために、SSL をサポートする必要があります。

セッション状態

HTTP 上の Git プロトコル(HTTP 自体と同様に)は、HTTP サーバー側の観点からはステートレスです。すべての状態は、クライアントプロセスによって保持および管理する必要があります。これにより、状態管理を心配することなく、サーバー側で単純なラウンドロビンロードバランシングが可能になります。

クライアントは、正しく機能するためにサーバー側での状態管理を要求しないでください。

サーバーは、正しく機能するために HTTP クッキーを要求しないでください。クライアントは、RFC 2616(HTTP/1.1)で説明されているように、要求処理中に HTTP クッキーを保存および転送できます。サーバーは、クライアントから送信されたクッキーを無視する必要があります。

一般的な要求処理

特に明記されている場合を除き、標準の HTTP 動作はクライアントとサーバーの両方で想定する必要があります。これには(ただし、これらに限定されない)が含まれます。

`$GIT_URL` にリポジトリがない場合、または `$GIT_URL` と一致する場所にアクセスできるリソースが存在しない場合、サーバーは `200 OK` レスポンスで応答してはなりません。サーバーは `404 Not Found`、`410 Gone`、または要求されたリソースが存在しないことを意味しないその他の適切な HTTP ステータスコードで応答する必要があります。

`$GIT_URL` にリポジトリがあるが、現在アクセスが許可されていない場合、サーバーは `403 Forbidden` HTTP ステータスコードで応答する必要があります。

サーバーは、HTTP 1.0 と HTTP 1.1 の両方をサポートする必要があります。サーバーは、要求とレスポンスの両方の本文に対してチャンクエンコーディングをサポートする必要があります。

クライアントは、HTTP 1.0 と HTTP 1.1 の両方をサポートする必要があります。クライアントは、要求とレスポンスの両方の本文に対してチャンクエンコーディングをサポートする必要があります。

サーバーは、ETag および/または Last-Modified ヘッダーを返すことができます。

クライアントは、If-Modified-Since および/または If-None-Match 要求ヘッダーを含めることで、キャッシュされたエンティティを再検証できます。

関連するヘッダーが要求に表示され、エンティティが変更されていない場合、サーバーは `304 Not Modified` を返すことができます。クライアントは、キャッシュされたエンティティを再利用することによって、`304 Not Modified` を `200 OK` と同じように処理する必要があります。

Cache-Control および/または Expires ヘッダーがキャッシングを許可する場合、クライアントは再検証せずにキャッシュされたエンティティを再利用できます。クライアントとサーバーは、キャッシュコントロールに関して RFC 2616 に従う必要があります。

参照の検出

すべての HTTP クライアントは、フェッチまたはプッシュ交換を開始するために、リモートリポジトリで使用可能な参照を検出する必要があります。

ダムクライアント

「ダム」プロトコルのみをサポートする HTTP クライアントは、リポジトリの特別な info/refs ファイルを要求することによって参照を検出する必要があります。

ダム HTTP クライアントは、検索/クエリパラメーターなしで、`$GIT_URL/info/refs` に対して `GET` 要求を行う必要があります。

C: GET $GIT_URL/info/refs HTTP/1.0
S: 200 OK
S:
S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31	refs/heads/maint
S: d049f6c27a2244e12041955e262a404c7faba355	refs/heads/master
S: 2cb58b79488a98d2721cea644875a8dd0026b115	refs/tags/v1.0
S: a3c2e2402b99163d1d59756e5f207ae21cccba4c	refs/tags/v1.0^{}

返された info/refs エンティティの Content-Type は `text/plain; charset=utf-8` である必要がありますが、任意のコンテンツタイプにすることができます。クライアントは、返された Content-Type の検証を試みないでください。ダムサーバーは、`application/x-git-` で始まる戻り値のタイプを返してはなりません。

返されたエンティティのキャッシングを無効にするために、Cache-Control ヘッダーを返すことができます。

レスポンスを調べる際には、クライアントは HTTP ステータスコードのみを調べる必要があります。有効なレスポンスは `200 OK` または `304 Not Modified` です。

返されたコンテンツは、各 ref とその既知の値を記述する UNIX 形式のテキストファイルです。ファイルは、C ロケール順序に従って名前でソートする必要があります。ファイルには、`HEAD` という名前のデフォルトの ref を含めないでください。

info_refs   =  *( ref_record )
ref_record  =  any_ref / peeled_ref
any_ref     =  obj-id HTAB refname LF
peeled_ref  =  obj-id HTAB refname LF
 obj-id HTAB refname "^{}" LF

スマートクライアント

「スマート」プロトコル(または「スマート」プロトコルと「ダム」プロトコルの両方)をサポートする HTTP クライアントは、リポジトリの info/refs ファイルに対してパラメーター化された要求を行うことによって参照を検出する必要があります。

要求には、`service=$servicename` というクエリパラメーターを正確に 1 つ含める必要があります。ここで、`$servicename` は、クライアントが操作を完了するために連絡しようとするサービス名である必要があります。要求に追加のクエリパラメーターを含めないでください。

C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0

ダムサーバーの応答

S: 200 OK
S:
S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31	refs/heads/maint
S: d049f6c27a2244e12041955e262a404c7faba355	refs/heads/master
S: 2cb58b79488a98d2721cea644875a8dd0026b115	refs/tags/v1.0
S: a3c2e2402b99163d1d59756e5f207ae21cccba4c	refs/tags/v1.0^{}

スマートサーバーの応答

S: 200 OK
S: Content-Type: application/x-git-upload-pack-advertisement
S: Cache-Control: no-cache
S:
S: 001e# service=git-upload-pack\n
S: 0000
S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
S: 003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
S: 0000

クライアントは、Git-Protocol HTTP ヘッダーでコロン区切りの文字列として追加パラメーターを送信できます(gitprotocol-pack[5] を参照)。

git-upload-pack[1] に `--http-backend-info-refs` オプションを使用します。

ダムサーバーの応答

ダムサーバーは、ダムサーバーの応答形式で応答する必要があります。

ダムクライアントの下の前のセクションで、ダムサーバーの応答の詳細な説明を参照してください。

スマートサーバーの応答

サーバーが要求されたサービス名を認識しない場合、またはサーバー管理者によって要求されたサービス名が無効になっている場合、サーバーは `403 Forbidden` HTTP ステータスコードで応答する必要があります。

それ以外の場合は、スマートサーバーは、要求されたサービス名に対してスマートサーバーの応答形式で応答する必要があります。

返されたエンティティのキャッシングを無効にするために、Cache-Control ヘッダーを使用する必要があります。

Content-Type は `application/x-$servicename-advertisement` である必要があります。クライアントは、別のコンテンツタイプが返された場合、ダムプロトコルにフォールバックする必要があります。ダムプロトコルにフォールバックする場合、クライアントは `$GIT_URL/info/refs` に追加の要求を行わず、代わりに既に手元にあるレスポンスを使用する必要があります。クライアントは、ダムプロトコルをサポートしていない場合は続行しないでください。

クライアントは、ステータスコードが `200 OK` または `304 Not Modified` であることを検証する必要があります。

クライアントは、レスポンスエンティティの先頭 5 バイトが正規表現 `^[0-9a-f]{4}#` と一致することを検証する必要があります。このテストに失敗した場合、クライアントは続行しないでください。

クライアントは、pkt-line レコードのシーケンスとして entire レスポンスを解析する必要があります。

クライアントは、最初の pkt-line が `# service=$servicename` であることを確認する必要があります。サーバーは、`$servicename` を要求パラメーター値に設定する必要があります。サーバーは、この行の末尾に LF を含める必要があります。クライアントは、行の末尾にある LF を無視する必要があります。

サーバーは、マジック `0000` エンド pkt-line マーカーでレスポンスを終了する必要があります。

返されたレスポンスは、各 ref とその既知の値を記述する pkt-line ストリームです。ストリームは、C ロケール順序に従って名前でソートする必要があります。ストリームには、最初の ref として `HEAD` という名前のデフォルトの ref を含める必要があります。ストリームには、最初の ref の後ろの NUL の後ろに機能宣言を含める必要があります。

追加パラメーターとして「version=1」が送信された場合、返されたレスポンスには「version 1」が含まれます。

smart_reply     =  PKT-LINE("# service=$servicename" LF)
     "0000"
     *1("version 1")
     ref_list
     "0000"
ref_list        =  empty_list / non_empty_list
empty_list      =  PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF)
non_empty_list  =  PKT-LINE(obj-id SP name NUL cap_list LF)
     *ref_record
cap-list        =  capability *(SP capability)
capability      =  1*(LC_ALPHA / DIGIT / "-" / "_")
LC_ALPHA        =  %x61-7A
ref_record      =  any_ref / peeled_ref
any_ref         =  PKT-LINE(obj-id SP name LF)
peeled_ref      =  PKT-LINE(obj-id SP name LF)
     PKT-LINE(obj-id SP name "^{}" LF

スマートサービス git-upload-pack

このサービスは、`$GIT_URL` が指すリポジトリから読み取ります。

クライアントは、最初に `$GIT_URL/info/refs?service=git-upload-pack` で ref 検出を実行する必要があります。

C: POST $GIT_URL/git-upload-pack HTTP/1.0
C: Content-Type: application/x-git-upload-pack-request
C:
C: 0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7\n
C: 0032have 441b40d833fdfa93eb2908e52742248faf0ee993\n
C: 0000
S: 200 OK
S: Content-Type: application/x-git-upload-pack-result
S: Cache-Control: no-cache
S:
S: ....ACK %s, continue
S: ....NAK

クライアントは、キャッシュされたレスポンスを再利用または再検証しないでください。サーバーは、レスポンスのキャッシングを防ぐために、十分な Cache-Control ヘッダーを含める必要があります。

サーバーは、ここで定義されているすべての機能をサポートする必要があります。

クライアントは、リクエストボディに少なくとも1つの "want" コマンドを送信する必要があります。クライアントは、サーバが機能allow-tip-sha1-in-wantまたはallow-reachable-sha1-in-wantをアドバタイズしていない限り、ref discoveryを通して取得したレスポンスに含まれていないidを "want" コマンド内で参照してはなりません。

compute_request   =  want_list
       have_list
       request_end
request_end       =  "0000" / "done"
want_list         =  PKT-LINE(want SP cap_list LF)
       *(want_pkt)
want_pkt          =  PKT-LINE(want LF)
want              =  "want" SP id
cap_list          =  capability *(SP capability)
have_list         =  *PKT-LINE("have" SP id LF)

TODO: これをさらに文書化します。

ネゴシエーションアルゴリズム

最小限のパックを選択する計算は、以下のとおりです(C = クライアント、S = サーバ)

初期ステップ

C: ref discoveryを使用して、アドバタイズされたrefsを取得します。

C: 認識されたオブジェクトをすべてセットadvertisedに入れます。

C: 後で両端にあると判断されたオブジェクトを保持するための空のセットcommonを作成します。

C: ref discovery中に見た内容に基づいて、クライアントがフェッチしたいadvertisedからのオブジェクトのセットwantを作成します。

C: コミット時間順に並べ替えられたキューc_pending(最新のものを最初にポップ)を開始します。すべてのクライアントrefsを追加します。コミットがキューからポップされると、その親は自動的に挿入されるべきです。コミットは一度だけキューに入る必要があります。

1回の計算ステップ

C: 1つの$GIT_URL/git-upload-packリクエストを送信します。

C: 0032want <want-#1>...............................
C: 0032want <want-#2>...............................
....
C: 0032have <common-#1>.............................
C: 0032have <common-#2>.............................
....
C: 0032have <have-#1>...............................
C: 0032have <have-#2>...............................
....
C: 0000

ストリームは「コマンド」に編成されており、各コマンドはpkt-lineに単独で表示されます。コマンドライン内では、最初のスペースまでのテキストがコマンド名であり、LFまでの行の残りが値です。コマンドラインは、pkt-line値の最後のバイトとしてLFで終了します。

コマンドは、リクエストストリームに表示される場合、以下の順序で表示する必要があります。

  • "want"

  • "have"

ストリームはpkt-lineフラッシュ(0000)で終了します。

単一のコマンド "want" または "have" は、値として1つの16進数形式のオブジェクト名を持つ必要があります。複数のオブジェクト名は、複数のコマンドを送信することで送信する必要があります。オブジェクト名は、object-format機能(デフォルトはSHA-1)を介してネゴシエートされたオブジェクト形式を使用して指定する必要があります。

haveリストは、c_pendingから最初の32個のコミットをポップすることによって作成されます。c_pendingが空になる場合は、それよりも少ない数を供給できます。

クライアントが256個の "have" コミットを送信し、まだs_commonからそれらのいずれかを返されていない場合、またはクライアントがc_pendingを空にした場合は、サーバに続行しないことを知らせるために "done" コマンドを含める必要があります。

C: 0009done

S: git-upload-packリクエストを解析します。

want内のすべてのオブジェクトがrefsから直接到達可能であることを確認します。

サーバは、わずかに古いリクエストを許可するために、履歴またはreflogをさかのぼって移動できます。

"want"オブジェクトが受信されない場合、エラーを送信します:TODO: "want"行が要求されない場合のエラーを定義します。

"want"オブジェクトが到達不能な場合、エラーを送信します:TODO: 無効な "want" が要求された場合のエラーを定義します。

空のリストs_commonを作成します。

"have"が送信された場合

クライアントによって供給された順序でオブジェクトをループ処理します。

各オブジェクトについて、サーバがrefから到達可能なオブジェクトを持っている場合、それをs_commonに追加します。コミットがs_commonに追加された場合、祖先を追加しないでください(祖先もhaveに表示されている場合でも)。

S: git-upload-packレスポンスを送信します。

サーバがパックするオブジェクトのクローズドセットを見つけたり、リクエストが "done" で終了した場合、パックで応答します。TODO: パックベースのレスポンスを文書化します。

S: PACK...

返されたストリームは、git-upload-packサービスによってサポートされているside-band-64kプロトコルであり、パックはストリーム1に埋め込まれています。サーバ側の進行状況メッセージは、ストリーム2に表示される場合があります。

ここで、「オブジェクトのクローズドセット」は、少なくとも1つの「want」から少なくとも1つの「common」オブジェクトへの少なくとも1つのパスを持つものとして定義されます。

サーバにもう少し情報が必要な場合、ステータス継続応答で返信します。TODO: 非パック応答を文書化します。

C: upload-packレスポンスを解析します:TODO: レスポンスの解析を文書化します。

別の計算ステップを実行します。

スマートサービスgit-receive-pack

このサービスは、`$GIT_URL` が指すリポジトリから読み取ります。

クライアントはまず、$GIT_URL/info/refs?service=git-receive-packでref discoveryを実行する必要があります。

C: POST $GIT_URL/git-receive-pack HTTP/1.0
C: Content-Type: application/x-git-receive-pack-request
C:
C: ....0a53e9ddeaddad63ad106860237bbf53411d11a7 441b40d833fdfa93eb2908e52742248faf0ee993 refs/heads/maint\0 report-status
C: 0000
C: PACK....
S: 200 OK
S: Content-Type: application/x-git-receive-pack-result
S: Cache-Control: no-cache
S:
S: ....

クライアントは、キャッシュされたレスポンスを再利用または再検証しないでください。サーバーは、レスポンスのキャッシングを防ぐために、十分な Cache-Control ヘッダーを含める必要があります。

サーバーは、ここで定義されているすべての機能をサポートする必要があります。

クライアントは、リクエストボディに少なくとも1つのコマンドを送信する必要があります。リクエストボディのコマンド部分では、クライアントはref discoveryを通して取得したidをold_idとして送信する必要があります。

update_request  =  command_list
     "PACK" <binary-data>
command_list    =  PKT-LINE(command NUL cap_list LF)
     *(command_pkt)
command_pkt     =  PKT-LINE(command LF)
cap_list        =  *(SP capability) SP
command         =  create / delete / update
create          =  zero-id SP new_id SP name
delete          =  old_id SP zero-id SP name
update          =  old_id SP new_id SP name

TODO: これをさらに文書化します。

Git

git[1]スイートの一部

scroll-to-top