Overall operation

  1. リモート側に接続し、 git-receive-pack を呼び出します。

  2. リモートが持っているref達と、リモートが指しているコミットを知ります。 それらを私たちがプッシュしているrefspec達にマッチさせます。

  3. 非早送り(non-fast-forwards)があるかどうかを確認します。 fetch-packとは異なり、早送りの場合、リポジトリ send-pack の実行は受信側のスーパーセットであると想定されるため、 want(欲しい)/have(持っている) やり取りの必要はなく、早送りチェックをローカルで実行できます。 結果をもう一方の側に伝えます。

  4. pack_objects() を呼び出して、パックファイルを生成し、それをもう一方の側に送信します。

  5. リモート側が十分に新しい場合(v1.1.0以降)、もう一方の側からのアンパックと、フックのステータスを待ちます。

  6. 適切なエラーコードで終了します。

Pack_objects pipeline

この関数は、ソケット(ネットワーク経由)、またはパイプ(ローカル)のいずれか1つのファイルデスクリプタ(fd)を取得します。 このfdに書き込まれる何かは、アンパックするために git-receive-pack に送られます。

send-pack ---> fd ---> receive-pack

関数 pack_objects は、パイプを作成してからフォークします。 フォークされた子は、標準入力からリビジョンパラメータを受け取るために、 --revs を指定して pack-objects を実行します。 このプロセスは、パックファイルをもう一方の側に書き込みます。

send-pack
   |
   pack_objects() ---> fd ---> receive-pack
      | ^ (pipe)
      v |
     (child)

子のdup2は、標準出力を相手側に戻し、標準入力をパイプから読み込むように手配します。 その後、pack-objects を実行します。 一方、親プロセスは、子プロセスのパイプラインへの供給を開始する前に、パイプラインの読み込み側と、receive-pack への fd を閉じます。

send-pack
   |
   pack_objects(parent)
      |
      v [0]
     pack-objects [0] ---> receive-pack

[jc: 以前のバグを理解する前は、パイプラインははるかに複雑でドキュメントが必要でしたが、 今ではとても単純です。]