日本語 ▾ トピック ▾ 最新バージョン ▾ gitprotocol-packは2.43.0で最終更新されました

名称

gitprotocol-pack - パックがネットワーク上で転送される仕組み

書式

<over-the-wire-protocol>

説明

Gitは、ssh://、git://、http://、およびfile://のトランスポートを介して、パックファイル形式でデータを転送することをサポートしています。プロトコルには2つのセットがあり、1つはクライアントからサーバーへデータをプッシュするためのもの、もう1つはサーバーからクライアントへデータをフェッチするためのものです。3つのトランスポート(ssh、git、file)はデータを転送するために同じプロトコルを使用します。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を含める**べき**ですが、受信者はLFが存在しなくても文句を言う**べきではありません**。

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

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

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

トランスポート

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

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

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

追加パラメータ

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

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

これらの追加パラメータを受信するサーバーは、認識できないすべてのキーを**無視しなければなりません**。現在、認識されている追加パラメータは、「version」のみで、値は*1*または*2*です。プロトコルバージョン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

ホストパラメータは、git-daemonの名前ベースの仮想ホスティングに使用されます。git daemonの--interpolated-pathオプションと、%H/%CH書式指定子を参照してください。

基本的に、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シェルを介して、それらのコマンドのいずれか、または両方を実行できる必要があります。一部のシステムでは、シェルアクセスはそれら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リポジトリが別のリポジトリが持っているデータを取得したい場合、最初のGitリポジトリは2番目のリポジトリからfetchできます。この操作は、サーバーが持っていてクライアントが持っていないデータを特定し、そのデータをパックファイル形式でクライアントにストリームします。

参照の発見

クライアントが最初に接続すると、サーバーは直ちにバージョン番号(「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コマンドの場合や、クライアントが既に最新である場合に発生します。

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

  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を参照してください。

すべてのwantおよびshallow(およびオプションの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)

クライアントが正の深度を要求した場合、サーバーは希望する深度よりも深くはないコミットのセットを計算します。コミットのセットはクライアントのwantedオブジェクトから開始されます。

サーバーは、結果として親が送信されない各コミットに対してshallow行を書き込みます。サーバーは、クライアントがシャローであると示したが、現在の要求深度ではもはやシャローではない(つまり、その親が今度は送信される)各コミットに対してunshallow行を書き込みます。サーバーは、クライアントがシャローであると示していないものをアンシャローとしてマーク**してはなりません**。

次に、クライアントはhave行を使用して所有しているobj-idのリストを送信し、サーバーがクライアントが必要とするオブジェクトのみを含むパックファイルを作成できるようにします。multi_ackモードでは、標準的な実装では一度に最大32個を送信し、その後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をACK obj-id ready行で区別し、特定された共通コミットをACK obj-id common行で示します。

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キューが空の場合に判断されます)、またはクライアントがあきらめることを決定した場合(標準的な実装では、サーバーからどれもACKされずに256個のhave行を送信した場合、つまり共通点がなくサーバーはすべてのオブジェクトを送信すべきであると判断した場合)、クライアントは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]

増分更新(fetch)応答は次のようになります。

   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機能が指定されている場合、サーバーはパックファイルデータを多重化して送信します。

各パケットは、続くデータ量のパケット行長で始まり、その後、続くデータがどのサイドバンドで来るかを示す単一バイトが続きます。

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

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

side-band機能が指定されなかった場合、サーバーは多重化せずにパックファイル全体をストリームします。

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

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

認証

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

参照の発見

参照発見フェーズは、フェッチプロトコルとほぼ同じ方法で行われます。サーバー上の各参照のobj-idと名前は、パケットライン形式でクライアントに送信され、その後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サーバーとの後方互換性のため、クライアントがプッシュ証明書とプッシュオプションを送信する場合、プッシュ証明書に埋め込まれたプッシュオプションとプッシュ証明書の後に続くプッシュオプションの両方を送信**しなければなりません**。(証明書内のプッシュオプションにはプレフィックスが付与されますが、証明書後のプッシュオプションには付与されません。)これら両方のリストは、プレフィックスを除いて同じで**なければなりません**。

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

  packfile          =  "PACK" 28*(OCTET)

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

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

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

作成または更新コマンドが使用された場合、サーバーが既に必要なすべてのオブジェクトを持っていても、パックファイルは送信**されなければなりません**。この場合、クライアントは空のパックファイルを送信**しなければなりません**。これが起こる可能性が高い唯一のケースは、クライアントが既存のobj-idを指す新しいブランチまたはタグを作成している場合です。

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

プッシュ証明書

プッシュ証明書はヘッダ行のセットから始まります。ヘッダと空行の後には、プロトコルコマンドが1行ずつ続きます。push-cert PKT-LINEの末尾のLFはオプションでは**ありません**。存在**しなければなりません**。

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

pusher識別子

GPGキーを「人間が読める名前 <email@address>」形式で識別します。

pushee URL

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

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