2013-01-18 14 views
9

この質問は本質的にはthisと似ていると私は前に言います。これを一意にする重要な違いが1つあります:生のgitプロトコル(基本的なパックネットワークプロトコルに精通していない場合はherehereを参照してください)を使用したいと思います。Gitはリモートリポジトリから単一のファイルをプログラムで取り出します

私は、匿名のgitリポジトリに接続するScalaとJGitを使用してアプリケーションを作成しています。私は単一のブロブを要求したい( "/path/to/file.txt" @ "refs/heads/branch1"と考える)。最終的に私の目標は、リモートリポジトリから単一のファイルをプログラムで取得することです。できることはかなり有用なもののようです。

私はこのプロトコルの内部について掘り下げて検討してきました。これの基本的なバージョンは "私はこれらのオブジェクトが必要です、私はこれらのオブジェクトを持っています"と思われます - そしてバム、あなたが持っていないすべてのパックファイルがあります。私の質問の中核は:の非再帰的なの方法で単一オブジェクトのgit-upload-packfileをどうやって尋ねるのですか?私は、単一のコミットオブジェクトをダウンロードしてから、木、次にサブツリー、次に別のサブツリー、そして最後にブロブそのものを求めてもOKです。スピードはあまり重要ではない、主に私は帯域幅を節約しようとしています。しかし、単にgit-upload-packfileに "私に求めているオブジェクトを与えてください"と言うことはできないようです。

はい、リポジトリのコンテンツに関する先験的な知識が必要です(ローカルリポジトリを持っていない、覚えています)。私はすべての可能なsha1のリストを生成し、私が望むものを除いてそれらのすべてを送ることができますが、それはばかげています(時間がかかり、帯域幅が消費され、あらゆる場所のプログラマーに対して犯罪になる)

もう一つの可能​​な解決策リモート側でgit-upload-archiveを使っているのですが、私はまだそれに目を向けていませんでした。

私はJGitを書き直したいと思っていますので、「どうすればJGitを行うのですか...」と読んでください。私は、プロトコルそのものがこれでも可能かどうかを知りたがっています。私が望むものを達成するためにプロトコルを乱用する素晴らしい方法があるように思えます。何かご意見は?

+0

"これはうまくいきません"との回答があると思います... " – twalberg

+0

@twalbergローカルレポは確かです。私がワイヤーでこれをすることができるかどうか不思議です。 –

+0

はい、ローカルリポジトリから1つのオブジェクトを抽出できます。ワイヤプロトコルはそれを行うようには設計されていませんでした。クローン/フェッチ(完全なリポジトリを避けるために浅いクローンを使用していても、まだコミット+ツリー+ブロブを取得する)をローカルリポジトリに適用してオブジェクトを抽出することで、最終目標を達成することができます。あなたが有線経由でそれをすることができるとは思わない(ただし、あなたがリモートへのsshアクセスを持っていれば、それを偽装することができるかもしれない)。 – twalberg

答えて

9

私自身の質問に答える。私は容認できる(ほとんど文書化されていないが)答えを見つけた。私はこれを理解するために多くのCコードを掘り下げなければならなかった。

まず、git-upload-packfileを使用して上記の要件を達成することはできません。なぜなら、これは単にプログラムが設計されたものではないからです。私が疑う正確な答えはgit-upload-archiveです。悲しいことに、プロトコルはALLではほとんど文書化されていません。他の誰かが同様の要件を持っている場合のために私のノートがここにあります。ソフトウェアを除き

git archive --format=tar --remote=ssh://[email protected]/cornballer.git \ 
    > master plans/documents/cornballer-blueprint.pdf | tar -x 

、うまくいけばJGitを使用して:私は(Scalaで)ここにシミュレートしようとしている基本的にはどのような

は、以下のコマンドです。残念ながら、JGitはgit archiveコマンドを(まだ)サポートしていません。ここでは、サポートを追加する方法(JGitをフォークして後で追加する方法)の非常に高度な概要を示します。

プロトコル(Documentation/technical/pack-protocolから)を見てみましょう。TXT):

  1. git-upload-archiveを実行するか、匿名のgitプロトコルを使用し、その後のいずれか(リモートSSHでの輸送を確立し)
  2. git-proto-request = request-command SP pathname NUL [ host-parameter NUL ] 
    request-command = "git-upload-pack"/"git-receive-pack"/
            "git-upload-archive" ; case sensitive 
    pathname   = *(%x01-ff) ; exclude NUL 
    host-parameter = "host=" hostname [ ":" port ] 
    

    だから、プロトコルの一部1は、このような何かを行きますgit-upload-archive /cornballer.git\0host=ssh.mycompany.com\0(パケットラインとして)

この時点で接続が確立されます。コマンドがサポートされていない場合、または何らかの問題があった場合は、エラーを返す可能性があります。私はまだこれを確認する方法を考え出していない。

次は、文書化されていない部分です。基本的には、git-archiveのコマンドライン引数を電信で送信します。それらはgit-archiveコマンドとまったく同じですが、1つの例外はすべて接頭辞argument[SPACE]です。各引数は、少なくとも参照実装では別のパケット行として記述されます。したがって、上記の例:

  1. は(フラッシュパケットを送信
  2. (パケットラインとして)argument plans/documents/cornballer-blueprint.pdfを送信
  3. (パケットラインなど)
  4. (パケットラインとして)argument masterを送信argument --format=tarを送ります0000

この時点では、リモートgit-archiveプロセスにコマンド全体を指定しました。今我々はその応答を読む。 -

  • NACK [message] - のみ検出されたエラーのいくつかの種類、

    1. ACK(アーカイブを送信する準備ができて、成功を意味する):私たちは、次のいずれかの応答になりますバックサーバから1本のパケットラインを読んでその使用の1つのインスタンス - 「サブプロセスを起動することができない」
    2. ERR [message] - エラーがACKが送信される場合、それはフラッシュパケット(0000)、次いで生Tが続く

    を発生しましたarデータ。この時点で、サイドバンド#1(メインデータチャネル)に入ってくるパケットラインを繰り返し読み取ります。フラッシュパケットに到達すると、読み込みを停止します。ものすごく単純。

    これでリモートファイルが作成されましたが、賢明なキャッシングをしたいのであればどうしますか?私がgit-upload-packfileを使用していた理由の1つは、コミットIDを記録し、それをローカルにキャッシュし、必要に応じてリフレッシュできることです。 tarファイルはその情報を私たちに教えてくれませんか?違う! gitのアーカイブのマニュアルページから

    タールフォーマットが を使用する場合にさらにコミットIDは、グローバル拡張PAXヘッダに格納されています。 git get-tar-commit-idを使用して抽出できます。 ZIPファイルでは、ファイルコメントとして として保存されます。

    これはすばらしいニュースです。それは文字通り私が望むすべてのものです。場合にはあなたがここに(ノー私はPAXヘッダを解剖するつもりはありません)サンプルだ、のようにヘッダが見えるか迷っている:

    pax_global_header00006660000000000000000000000064121002672560014513gustar00rootroot0000000000000052 comment=326756f834865880c9832b64238e7665632e9b67 
    

    だから、私の観点から、私は単純に、自動的にパイプラインを設定する必要があります上記の手順を実行して、プログラム上でuntarステップを実行して、目的の「gitから単一のファイルを取得する」機能を実行します。

  • +0

    素晴らしい仕事!私は先日、この問題で刺すようになりましたが、それほど遠くには行きませんでした(しかし 'git-upload-packfile'だけを見ていました)。 –

    +0

    @Greg thanks :) –

    関連する問題