Git
英語 ▾ トピック ▾ 最新バージョン ▾ gitprotocol-pack 最終更新日 2.43.0

名前

gitprotocol-pack - パックファイルのネットワーク転送方法

概要

<over-the-wire-protocol>

説明

Git は、ssh://、git://、http://、および file:// トランスポートを介してパックファイル内のデータを転送できます。クライアントからサーバーへのデータプッシュと、サーバーからクライアントへのデータフェッチの2つのプロトコルセットがあります。ssh、git、fileの3つのトランスポートは、同じプロトコルを使用してデータを転送します。httpについては、gitprotocol-http[5]を参照してください。

標準的なGit実装で呼び出されるプロセスは、データフェッチの場合はサーバー側でupload-pack、クライアント側でfetch-packです。データプッシュの場合は、サーバー側でreceive-pack、クライアント側でsend-packです。このプロトコルは、サーバーがクライアントにサーバー上の現在の状態を伝え、その後、互いを完全に更新するために送信する必要のある最小限のデータ量を交渉するために機能します。

pkt-line形式

以下の説明は、gitprotocol-common[5]で説明されているpkt-line形式に基づいています。文法でPKT-LINE(...)が示されている場合、特に明記されていない限り、通常のpkt-line LFルールが適用されます。送信者はLFを含めるべきですが、受信者は存在しない場合に文句を言うべきではありません。

エラーパケットは、エラー文字列を含む特別なpkt-lineです。

  error-line     =  PKT-LINE("ERR" SP explanation-text)

プロトコル全体で、PKT-LINE(...)が期待される場合、エラーパケットを送信できます。クライアントまたはサーバーがこのパケットを送信すると、このプロトコルで定義されたデータ転送プロセスは終了します。

トランスポート

パックファイルプロトコルが開始されるトランスポートは3つあります。Gitトランスポートは、クライアントが通信したいコマンド(ほとんどの場合upload-packですが、Gitサーバーはグローバルに書き込み可能に構成できるため、receive-packの開始も許可されます)を受け取り、それを実行して要求プロセスに接続する単純な、認証されていないサーバーです。

SSHトランスポートでは、クライアントはSSHプロトコルを介してサーバー上でupload-packまたはreceive-packプロセスを実行し、その呼び出されたプロセスとSSH接続を介して通信します。

file://トランスポートは、upload-packまたはreceive-packプロセスをローカルで実行し、パイプを介して通信します。

追加パラメータ

このプロトコルは、クライアントがサーバーへの最初のメッセージに追加情報を送信できるメカニズムを提供します。これらは「追加パラメータ」と呼ばれ、Git、SSH、およびHTTPプロトコルでサポートされています。

各追加パラメータは、<key>=<value>または<key>の形式を取ります。

このような追加パラメータを受信するサーバーは、認識されないキーをすべて無視する必要があります。現在、認識されている追加パラメータは、値が1または2の「version」だけです。プロトコルバージョン2の詳細については、gitprotocol-v2[5]を参照してください。

Gitトランスポート

Gitトランスポートは、pkt-line形式を使用してワイヤ上でコマンドとリポジトリを送信することから始まり、その後にNULバイトとホスト名パラメータが続き、NULバイトで終了します。

0033git-upload-pack /project.git\0host=myserver.com\0

トランスポートは、追加のNULバイトを追加し、1つ以上のNULで終端された文字列を追加することで、追加パラメータを送信できます。

003egit-upload-pack /project.git\0host=myserver.com\0\0version=1\0
git-proto-request = request-command SP pathname NUL
      [ host-parameter NUL ] [ NUL extra-parameters ]
request-command   = "git-upload-pack" / "git-receive-pack" /
      "git-upload-archive"   ; case sensitive
pathname          = *( %x01-ff ) ; exclude NUL
host-parameter    = "host=" hostname [ ":" port ]
extra-parameters  = 1*extra-parameter
extra-parameter   = 1*( %x01-ff ) NUL

host-parameterは、git-daemonのnameベースの仮想ホスティングに使用されます。%H/%CH形式文字を含むgit daemonの--interpolated-pathオプションを参照してください。

基本的に、GitクライアントがGitプロトコルを介してサーバー側のupload-packプロセスに接続するために実行していることは次のとおりです。

$ echo -e -n \
  "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" |
  nc -v example.com 9418

SSHトランスポート

SSHを介してupload-packまたはreceive-packプロセスを開始するには、SSHリモート実行を使用してサーバー上のバイナリを実行します。これは基本的に次の実行と同等です。

$ ssh git.example.com "git-upload-pack '/project.git'"

サーバーが特定のユーザーに対してSSHを介したGitのプッシュとプルをサポートするには、そのユーザーがログイン時に提供されるSSHシェルを介してそれらのコマンドの1つまたは両方を実行できる必要があります。一部のシステムでは、そのシェルアクセスは、それらの2つのコマンドのみ、またはそのうちの1つのみを実行できるよう制限されています。

ssh://形式のURIでは、URI内で絶対パスであるため、ホスト名(またはポート番号)の後の/は引数として送信され、リモートgit-upload-packによってそのまま読み取られるため、リモートファイルシステム内の絶対パスとして機能します。

   git clone ssh://user@example.com/project.git
  |
  v
ssh user@example.com "git-upload-pack '/project.git'"

"user@host:path"形式のURIでは、ユーザーのホームディレクトリを基準とした相対パスです。Gitクライアントは次を実行するためです。

   git clone user@example.com:project.git
    |
    v
ssh user@example.com "git-upload-pack 'project.git'"

例外は、~が使用されている場合で、その場合は先頭の/なしで実行します。

   ssh://user@example.com/~alice/project.git,
    |
    v
ssh user@example.com "git-upload-pack '~alice/project.git'"

protocol.version構成変数の値によっては、GitはGIT_PROTOCOL環境変数にコロン区切りの文字列として追加パラメータを送信しようとします。これは、ssh.variant構成変数がsshコマンドが引数として環境変数の受け渡しをサポートしていることを示している場合のみ実行されます。

ここで覚えておくべき点がいくつかあります。

  • "コマンド名"はダッシュで記述されています(例:git-upload-pack)。ただし、これはクライアントによってオーバーライドできます。

  • リポジトリパスは常に一重引用符で囲まれています。

サーバーからのデータフェッチ

あるGitリポジトリが別のリポジトリが持つデータを取得したい場合、最初のリポジトリは2番目のリポジトリからフェッチできます。この操作は、サーバーがクライアントが持たないデータを特定し、そのデータをパックファイル形式でクライアントにストリーミングします。

参照の検出

クライアントが最初に接続すると、サーバーはすぐにバージョン番号(「version=1」が追加パラメータとして送信されている場合)、および各参照(すべてのブランチとタグ)とその参照が現在指しているオブジェクト名の一覧を返します。

 $ echo -e -n "0045git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
    nc -v example.com 9418
 000eversion 1
 00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
side-band side-band-64k ofs-delta shallow no-progress include-tag
 00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
 003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
 003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
 003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
 003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
 0000

返された応答は、各参照とその現在の値を記述するpkt-lineストリームです。ストリームは、Cロケール順序に従って名前でソートする必要があります。

HEADが有効な参照の場合、HEADは最初に宣伝された参照として表示される必要があります。HEADが無効な参照の場合、HEADは広告リストにまったく表示されない必要がありますが、他の参照は表示される可能性があります。

ストリームには、最初の参照の後ろのNULの後ろに機能宣言を含める必要があります。参照の展開された値(つまり「ref^{}」)は、存在する場合、参照の直後に表示する必要があります。準拠するサーバーは、それが注釈付きタグの場合、参照を展開する必要があります。

  advertised-refs  =  *1("version 1")
		      (no-refs / list-of-refs)
		      *shallow
		      flush-pkt

  no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
		      NUL capability-list)

  list-of-refs     =  first-ref *other-ref
  first-ref        =  PKT-LINE(obj-id SP refname
		      NUL capability-list)

  other-ref        =  PKT-LINE(other-tip / other-peeled)
  other-tip        =  obj-id SP refname
  other-peeled     =  obj-id SP refname "^{}"

  shallow          =  PKT-LINE("shallow" SP obj-id)

  capability-list  =  capability *(SP capability)
  capability       =  1*(LC_ALPHA / DIGIT / "-" / "_")
  LC_ALPHA         =  %x61-7A

サーバーとクライアントは、obj-idに小文字を使用する必要があり、どちらもobj-idを大文字と小文字を区別しないものとして扱う必要があります。

許可されるサーバー機能と説明の一覧については、protocol-capabilities.txtを参照してください。

パックファイルのネゴシエーション

参照と機能の検出後、クライアントはflush-pktを送信して接続を終了することにより、パックデータが不要になった場合、サーバーが正常に終了して切断できるようにすることができます。これはls-remoteコマンドで発生し、クライアントが既に最新の状態である場合にも発生する可能性があります。

それ以外の場合は、ネゴシエーションフェーズに入り、クライアントとサーバーは、サーバーに要求するオブジェクト、浅いオブジェクト(存在する場合)、および要求する最大コミット深度(存在する場合)をサーバーに伝えることで、転送に必要な最小限のパックファイルを決定します。クライアントは、サーバーが最初に言ったことができる機能の中から、有効にしたい機能のリストも送信します。

  upload-request    =  want-list
		       *shallow-line
		       *1depth-request
		       [filter-request]
		       flush-pkt

  want-list         =  first-want
		       *additional-want

  shallow-line      =  PKT-LINE("shallow" SP obj-id)

  depth-request     =  PKT-LINE("deepen" SP depth) /
		       PKT-LINE("deepen-since" SP timestamp) /
		       PKT-LINE("deepen-not" SP ref)

  first-want        =  PKT-LINE("want" SP obj-id SP capability-list)
  additional-want   =  PKT-LINE("want" SP obj-id)

  depth             =  1*DIGIT

  filter-request    =  PKT-LINE("filter" SP filter-spec)

クライアントは、参照検出フェーズから必要なすべてのobj-idをwant行として送信する必要があります。クライアントは、要求本文に少なくとも1つのwantコマンドを送信する必要があります。クライアントは、参照検出によって取得された応答に表示されなかったobj-idをwantコマンドに記述してはなりません。

クライアントは、浅いコピーのみを持っている(つまり、コミットの親を持っていない)すべてのobj-idをshallow行として記述する必要があります。これにより、サーバーはクライアントの履歴の制限を認識できます。

クライアントは、このトランザクションで必要な最大コミット履歴深度をdeepen行としてオプションで要求できます。これは、履歴の先端からのコミット数です。深さが0の場合、深さの要求を行わないことと同じです。クライアントは、この深度を超えたコミットを受信したくなく、それらのコミットを完了するためにのみ必要なオブジェクトも必要としません。結果として親が受信されないコミットは、浅いものとして定義され、サーバーでそのようにマークされます。この情報は、次のステップでクライアントに送信されます。

クライアントは、いくつかのフィルタリング手法のいずれかを使用して、pack-objectsがパックファイルからさまざまなオブジェクトを省略するようにオプションで要求できます。これらは、部分クローンと部分フェッチ操作で使用することを目的としています。フィルタ指定値を満たさないオブジェクトは、want行で明示的に要求されていない限り、省略されます。可能なフィルタ指定値については、rev-listを参照してください。

すべてのwantshallow(およびオプションのdeepen)が転送されると、クライアントはflush-pktを送信して、リストの送信が完了したことをサーバー側に通知する必要があります。

それ以外の場合、クライアントが正の深度要求を送信した場合、サーバーはどのコミットが浅くなるかを決定し、この情報をクライアントに送信します。クライアントが正の深度を要求しなかった場合、このステップはスキップされます。

  shallow-update   =  *shallow-line
		      *unshallow-line
		      flush-pkt

  shallow-line     =  PKT-LINE("shallow" SP obj-id)

  unshallow-line   =  PKT-LINE("unshallow" SP obj-id)

クライアントが正のdepthを要求した場合、サーバーは目的のdepthよりも浅いコミットの集合を計算します。コミットの集合は、クライアントのwantsから始まります。

サーバーは、その親が送信されないコミットごとにshallow行を書き込みます。また、クライアントがshallowであると指示したものの、現在要求されたdepthではshallowではなくなった(つまり、その親が送信されるようになった)コミットごとにunshallow行を書き込みます。サーバーは、クライアントがshallowであると指示しなかったものをunshallowとしてマークしてはなりません。

次に、クライアントはhave行を使用して保持しているobj-idのリストを送信し、サーバーはクライアントが必要とするオブジェクトのみを含むパックファイルを作成できます。multi_ackモードでは、標準の実装では一度に最大32個のhave行を送信し、その後flush-pktを送信します。標準の実装では、次の32個をすぐに送信するため、常に32個のブロックが「送信中」になります。

  upload-haves      =  have-list
		       compute-end

  have-list         =  *have-line
  have-line         =  PKT-LINE("have" SP obj-id)
  compute-end       =  flush-pkt / PKT-LINE("done")

サーバーがhave行を読み取ると、クライアントが保持していると述べたobj-idのうち、サーバーも保持しているものに対してACKを返します。サーバーは、クライアントが選択したackモードに応じて、obj-idに対するACKを異なる方法で返します。

multi_ackモードでは

  • サーバーは、共通のコミットに対してACK obj-id continueで応答します。

  • サーバーが許容可能な共通のベースコミットを見つけ、パックファイルを作成する準備ができると、すべてのhave obj-idをクライアントに盲目的にACKします。

  • その後、サーバーはNAKを送信し、クライアントからの次の応答(doneまたは別のhave行のリスト)を待ちます。

multi_ack_detailedモードでは

  • サーバーは、データの送信準備ができていることを示すACK obj-id ready行と、識別された共通のコミットを示すACK obj-id common行でACKを区別します。

multi_ackとmulti_ack_detailedのどちらも使用しない場合

  • upload-packは、最初に共通のオブジェクトが見つかったときに"ACK obj-id"を送信します。その後、クライアントが"done"を送信するまで何も送信しません。

  • 共通のオブジェクトがまだ見つかっていない場合、upload-packはflush-pktに対して"NAK"を送信します。共通のオブジェクトが見つかっており、既にACKが送信されている場合は、flush-pktに対して何も送信しません。

クライアントは、サーバーが効率的なパックファイルを送信するのに十分な情報を持っていると判断できるだけのACK応答を受け取ると(標準の実装では、残りの`--date-order`キュー内のすべてをサーバーと共通のものとして色付けできるだけのACKを受け取るか、`--date-order`キューが空になることで判断されます)、またはクライアントが諦めたいと判断すると(標準の実装では、クライアントが256個のhave行を送信してもサーバーからACKされないことで判断されます - 共通するものがなく、サーバーはすべてのオブジェクトを送信する必要があることを意味します)、doneコマンドを送信します。doneコマンドは、クライアントがパックファイルデータの受信準備ができていることをサーバーに知らせます。

ただし、256個の制限は、以前のラウンドで少なくとも1つの"ACK %s continue"を受け取った場合にのみ、標準のクライアント実装で有効になります。これは、完全に諦める前に少なくとも1つの共通の祖先が見つかるようにするためです。

クライアントからdone行が読み取られると、サーバーは最終的なACK obj-idを送信するか、NAKを送信します。obj-idは、共通であると判断された最後のコミットのオブジェクト名です。サーバーは、少なくとも1つの共通のベースがあり、multi_ackまたはmulti_ack_detailedが有効になっている場合にのみ、done後にACKを送信します。共通のベースが見つからない場合は、サーバーは常にdone後にNAKを送信します。

ACKまたはNAKの代わりに、サーバーはエラーメッセージを送信する場合があります(たとえば、クライアントから受信したwant行内のオブジェクトを認識できない場合など)。

その後、サーバーはパックファイルデータの送信を開始します。

  server-response = *ack_multi ack / nak
  ack_multi       = PKT-LINE("ACK" SP obj-id ack_status)
  ack_status      = "continue" / "common" / "ready"
  ack             = PKT-LINE("ACK" SP obj-id)
  nak             = PKT-LINE("NAK")

(have行のない)単純なクローンは次のようになります。

   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
     side-band-64k ofs-delta\n
   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
   C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
   C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
   C: 0000
   C: 0009done\n

   S: 0008NAK\n
   S: [PACKFILE]

増分更新(フェッチ)レスポンスは次のようになります。

   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
     side-band-64k ofs-delta\n
   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
   C: 0000
   C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
   C: [30 more have lines]
   C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
   C: 0000

   S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
   S: 0008NAK\n

   C: 0009done\n

   S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
   S: [PACKFILE]

パックファイルデータ

クライアントとサーバーは、クライアントに送信する必要がある最小限のデータ量についてネゴシエーションを完了したので、サーバーは必要なデータをパックファイル形式で構築して送信します。

パックファイル自体の実際の内容については、gitformat-pack[5]を参照してください。

クライアントによってside-bandまたはside-band-64k機能が指定されている場合、サーバーは多重化されたパックファイルデータを送信します。

各パケットは、それに続くデータ量のpacket-line長で始まり、それに続くデータがどのサイドバンドから来ているかを指定する1バイトが続きます。

side-bandモードでは、最大999バイトのデータと1つの制御コードを送信し、合計最大1000バイトをpkt-lineに含めます。side-band-64kモードでは、最大65519バイトのデータと1つの制御コードを送信し、合計最大65520バイトをpkt-lineに含めます。

サイドバンドバイトは12、または3になります。サイドバンド1にはパックファイルデータが含まれ、サイドバンド2はクライアントが一般的にstderrに出力する進捗情報に使用され、サイドバンド3はエラー情報に使用されます。

side-band機能が指定されていない場合、サーバーは多重化せずにパックファイルをストリーミングします。

サーバーへのデータのプッシュ

サーバーへのデータのプッシュは、サーバー上のreceive-packプロセスを呼び出します。これにより、クライアントは更新する参照をサーバーに伝え、それらの新しい参照を完成させるためにサーバーが必要とするすべてのデータを送信できます。すべてのデータが受信され検証されると、サーバーは参照をクライアントが指定したものに更新します。

認証

プロトコル自体には認証メカニズムが含まれていません。SSHなどのトランスポートによって、receive-packプロセスが呼び出される前に処理されます。Gitトランスポートを介してreceive-packが構成されている場合、それらのリポジトリは、そのポート(9418)にアクセスできる人であれば誰でも書き込み可能になります。これは、そのトランスポートが認証されていないためです。

参照の検出

参照の検出フェーズは、フェッチプロトコルとほぼ同じ方法で行われます。サーバー上の各参照obj-idと名前は、packet-line形式でクライアントに送信され、flush-pktが続きます。唯一の違いは、機能リストが異なることです。可能な値は、report-statusreport-status-v2delete-refsofs-deltaatomic、およびpush-optionsのみです。

参照更新要求とパックファイル転送

クライアントはサーバーの参照が何であるかを知ると、参照更新要求のリストを送信できます。更新するサーバー上の各参照について、サーバー上に現在あるobj-id、クライアントが更新したいobj-id、および参照の名前をリストした行を送信します。

このリストの後にflush-pktが続きます。

  update-requests   =  *shallow ( command-list | push-cert )

  shallow           =  PKT-LINE("shallow" SP obj-id)

  command-list      =  PKT-LINE(command NUL capability-list)
		       *PKT-LINE(command)
		       flush-pkt

  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

  old-id            =  obj-id
  new-id            =  obj-id

  push-cert         = PKT-LINE("push-cert" NUL capability-list LF)
		      PKT-LINE("certificate version 0.1" LF)
		      PKT-LINE("pusher" SP ident LF)
		      PKT-LINE("pushee" SP url LF)
		      PKT-LINE("nonce" SP nonce LF)
		      *PKT-LINE("push-option" SP push-option LF)
		      PKT-LINE(LF)
		      *PKT-LINE(command LF)
		      *PKT-LINE(gpg-signature-lines LF)
		      PKT-LINE("push-cert-end" LF)

  push-option       =  1*( VCHAR | SP )

サーバーがpush-options機能をアドバタイズしており、クライアントが上記の機能リストの一部としてpush-optionsを指定している場合、クライアントはプッシュオプションを送信し、その後にflush-pktを送信します。

  push-options      =  *PKT-LINE(push-option) flush-pkt

古いGitサーバーとの下位互換性のために、クライアントがプッシュ証明書とプッシュオプションを送信する場合、プッシュ証明書に埋め込まれたプッシュオプションと、プッシュ証明書の後のプッシュオプションの両方を送信する必要があります。(証明書内のプッシュオプションには接頭辞が付きますが、証明書後のプッシュオプションには接頭辞が付かないことに注意してください)。これら2つのリストは、接頭辞を除いて同じである必要があります。

その後、サーバーが新しい参照を完成させるために必要なすべてのオブジェクトを含むパックファイルが送信されます。

  packfile          =  "PACK" 28*(OCTET)

受信側がdelete-refsをサポートしていない場合、送信側は削除コマンドを要求してはなりません。

受信側がpush-certをサポートしていない場合、送信側はpush-certコマンドを送信してはなりません。push-certコマンドが送信されると、command-listを送信してはなりません。代わりに、プッシュ証明書に記録されたコマンドが使用されます。

使用されるコマンドがdeleteのみの場合は、パックファイルを送信してはなりません。

createまたはupdateコマンドが使用されている場合、サーバーが既に必要なすべてのオブジェクトを持っている場合でも、パックファイルを送信する必要があります。この場合、クライアントは空のパックファイルを送信する必要があります。これは、クライアントが既存のobj-idを指す新しいブランチまたはタグを作成する場合にのみ発生する可能性があります。

サーバーはパックファイルを受信し、解凍し、更新中の各参照が要求処理中に変更されていないことを検証し(obj-idは古いidと同じです)、更新が許容可能であることを確認するために更新フックを実行します。すべてが問題なければ、サーバーは参照を更新します。

プッシュ証明書

プッシュ証明書は、ヘッダー行のセットで始まります。ヘッダーと空行の後に、プロトコルコマンドが1行ずつ続きます。プッシュ証明書PKT-LINEの末尾のLFは必須です。

現在、次のヘッダーフィールドが定義されています。

pusher ident

"Human Readable Name <email@address>"形式でGPGキーを識別します。

pushee url

git pushを実行したユーザーがプッシュしようとしたリポジトリURL(URLに認証情報が含まれている場合は匿名化されます)。

nonce nonce

受信リポジトリがプッシャーに証明書に含めるように要求したnonce文字列(リプレイ攻撃を防ぐため)。

GPG署名行は、署名ブロックが始まる前のプッシュ証明書に記録された内容に対する分離署名です。分離署名は、コマンドがプッシャー(署名者でなければならない)によって与えられたことを証明するために使用されます。

状態の報告

送信者からパックデータを受信した後、受信者はreport-statusまたはreport-status-v2機能が有効な場合にレポートを送信します。これは、その更新で発生したことを簡潔にリストしたものです。まず、パックファイルの解凍の状態をunpack okまたはunpack [error]としてリストします。次に、更新しようとした各参照の状態をリストします。各行は、更新が成功した場合はok [refname]、更新が失敗した場合はng [refname] [error]です。

  report-status     = unpack-status
		      1*(command-status)
		      flush-pkt

  unpack-status     = PKT-LINE("unpack" SP unpack-result)
  unpack-result     = "ok" / error-msg

  command-status    = command-ok / command-fail
  command-ok        = PKT-LINE("ok" SP refname)
  command-fail      = PKT-LINE("ng" SP refname SP error-msg)

  error-msg         = 1*(OCTET) ; where not "ok"

report-status-v2機能は、proc-receiveフックによって書き換えられた参照のレポートをサポートするために、新しいオプション行を追加することでプロトコルを拡張します。proc-receiveフックは、擬似参照に対するコマンドを処理することができ、これにより1つ以上の参照が作成または更新される可能性があり、各参照は異なる名前、異なるnew-oid、および異なるold-oidを持つ可能性があります。

  report-status-v2  = unpack-status
		      1*(command-status-v2)
		      flush-pkt

  unpack-status     = PKT-LINE("unpack" SP unpack-result)
  unpack-result     = "ok" / error-msg

  command-status-v2 = command-ok-v2 / command-fail
  command-ok-v2     = command-ok
		      *option-line

  command-ok        = PKT-LINE("ok" SP refname)
  command-fail      = PKT-LINE("ng" SP refname SP error-msg)

  error-msg         = 1*(OCTET) ; where not "ok"

  option-line       = *1(option-refname)
		      *1(option-old-oid)
		      *1(option-new-oid)
		      *1(option-forced-update)

  option-refname    = PKT-LINE("option" SP "refname" SP refname)
  option-old-oid    = PKT-LINE("option" SP "old-oid" SP obj-id)
  option-new-oid    = PKT-LINE("option" SP "new-oid" SP obj-id)
  option-force      = PKT-LINE("option" SP "forced-update")

更新は、いくつかの理由で失敗する可能性があります。参照は、参照検出フェーズが最初に送信されて以降に変更されている可能性があり、つまりその間に誰かがプッシュしたということです。プッシュされている参照はノンファストフォワード参照である可能性があり、更新フックまたは設定がそれを許可しないように設定されている可能性などもあります。また、一部の参照は更新される一方で、他の参照は拒否される可能性があります。

クライアント/サーバー間の通信の例を以下に示します。

   S: 006274730d410fcb6603ace96f1dc55ea6196122532d refs/heads/local\0report-status delete-refs ofs-delta\n
   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
   S: 003d74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
   S: 0000

   C: 00677d1665144a3a975c05f1f43902ddaf084e784dbe 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
   C: 006874730d410fcb6603ace96f1dc55ea6196122532d 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
   C: 0000
   C: [PACKDATA]

   S: 000eunpack ok\n
   S: 0018ok refs/heads/debug\n
   S: 002ang refs/heads/master non-fast-forward\n

GIT

git[1]スイートの一部

scroll-to-top