5

ローカル Git リポジトリにリモート サーバーからの更新が必要かどうかを手動で確認するときは、git remote show upstreamその出力を実行して解釈します。しかし今、Git サポートを追加する Python アプリケーション内でこれを実行しようとしています。

実際、私はリモート サーバー上の特定のブランチが特定のローカル ブランチと異なるかどうかを判断しようとしています。異なる場合は、関係がどのようになっているのか (早送り可能、前方、後方、分岐)。

git rev-list master..upstream/masterと ?の結果を比較することで、それを行う方法を知っています。git rev-list upstream/master..master. ただし、これはリモートサーバーからフェッチした後にのみ機能します。

最初にフェッチせずにそのような比較を行う方法はありますか?
用途の 1 つは、アプリケーション自体を更新することです。これには、最初にフェッチしても問題ないと思います。しかし、登録されているすべてのリモートとそのブランチを調べて、ユーザーがどこでさらに多くのものを入手できるかを伝えたいとも考えています。ユーザーがほとんどのリモートを必要としない可能性があるため、最初にすべてのリモートを取得することは受け入れられないと思います。

探しls-remoteているコマンドだと思いますが、必要なものをどのように達成できるかわかりません。との結果比較しgit ls-remote --heads upstreamて違いgit rev-parse HEAD^あるかどうかを判断できますが、どうすればよいかわかりません。コミットの完全なリストを取得し、それをローカル コミットのリストと手動で比較するため に使用する必要がありますか? 実際、リモートリポジトリでも機能する同等のものを見つけたいと思っています。多分誰かがその比較を どのように実行するか知っていますか?
git ls-remote upstreamgit rev-list
git remote show upstream


編集: @torek: 詳細な回答をありがとうございました。消化するのに少し時間がかかりますが、より生産的な時間にそれを見ていきます
. おそらく、いくつかのことはあなたが思っているよりも単純です (なぜなら、私は一般的な Git GUI クライアントのようなことをしていないからです)。

Github でホストされている既存の Python アプリケーションがあります。主な開発者のみがリポジトリへのプッシュ アクセスを持ち、彼は自分のmasterブランチのみを公開します。

ダウンロード可能なパッケージを使用するユーザーと、Git リポジトリからアプリケーションを実行するユーザーがいます (これは、インタープリター言語として Python で特に役立ちます)。

私が現在実装している最初のことは、Git を介してアプリケーション自体を更新するためのアプリケーション内からのインターフェイスです。(わかりました、それは本当に画期的なことではありません。誰もがコマンドラインに行っgit pull origin masterてリモートに名前を付けたり、発行したりできるからです。しかし、私はこれを、より高度なツールがアプリケーションのドキュメント/プロジェクト. 「更新の確認」ボタンをクリックする人がフェッチを受け入れることが期待されているため、
これはいつでもOKです. また、すべてがどのように機能するかは非常に明確です. URLを見てリモートの名前を判断しますfetch「公式」リポジトリを指しているものが(複数ある場合)どれかを知ってください。

しかし、同時に貢献者であるユーザー (私のような) もいます。彼らは通常、リポジトリをフォークしているため、少なくとも 2 つのリモート (メイン リポジトリと個人のフォーク) を持っています。master にマージされる前に自分の貢献を検査するために、他のユーザーのフォークも登録している場合があります。プル リクエストに近づいているとき、プル リクエスト前のフィードバックを提供するために、新しい資料を取得するように頼むこともあります。

私が今達成しようとしているのは、基本的に、すべてのリモートのすべてのブランチのリストと、それらのどれに新しい素材があり、おそらくどのように関連しているかに関する情報upstream/masterです。たとえば、マスター 17 コミット後に分岐され、上流のリポジトリに含まれていない 12 のコミットが含まれていることを伝えます。
私の推論は、これらすべてのリモート ブランチを完全に (そして定期的に) 取得するのは適切な動作ではないということです。ユーザーは、実際に検査したいブランチのみをフェッチする必要があると思います。

しかし、あなたの答えを最初に読んだときから、バックグラウンドですべてをフェッチしてから、ローカルブランチと「ローカルリモート」ブランチの比較を解釈することになるかもしれません。

4

1 に答える 1

7

故障中:

実際、リモートリポジトリでも動作する git rev-list に相当するものを見つけたいと思っています。

1つもありません。一部のリモートに含まれていないコミットの数を確認たい場合、これは以下で重要です。

実際、私はリモート サーバー上の特定のブランチが特定のローカル ブランチと異なるかどうかを判断しようとしています。異なる場合は、関係がどのようになっているのか (早送り可能、前方、後方、分岐)。...最初に取得せずにそのような比較を行う方法はありますか?

まあ、主にいいえ、ただし、これは、ここでどの程度文字通りになりたいか、および結果がどれだけ正確に必要かによって部分的に異なります. また、リモートから切断して更新を取得した直後に、他の誰かが同じリモートに接続してすべてを変更する可能性があることに注意してください。リモートも1 つしかないかのように作成しました。複数のリモートがある場合があります。

を使用git fetchすると、リモートに接続し、参照 (主にブランチ ヘッドとタグだけでなく、git ノートなども含む) に関してクエリを実行し、必要に応じて新しいものを持ち込みます。

を使用git ls-remoteすると、リモートへの接続が確立され、クエリが実行されます (そして、そこで停止します)。

したがって、リモートに「到達しにくい」場合 (たとえば、接続の確立に 1 ~ 2 秒かかる、または ssh パスワードやフレーズなどの入力が必要) であるが、更新が小さいか高速である (接続が確立されると、転送はfetch後で 2 番目の接続を作成するのは面倒なので、単純な方が経済的です。「簡単にアクセスできる」が、更新が大きくて遅い場合は、ls-remote. しかし、いずれにせよ、リモートへの接続を行っています。これは、 fetch. また、中間のコミット ID を一覧表示する必要がある場合、それらのコミットを持ち込む必要があるため、完全に実行する必要がありますfetch

もう 1 つのしわがありfetchます。

git ls-remoteサンプル出力を見てみましょうgit remote show origin。最初に実行しますgit fetch origin(ただし、既に最新であるため、出力はありません)。

$ git fetch origin
$ git ls-remote origin
120a630b0b71193a33cd033ae9ddcee1db3df07e    HEAD
120a630b0b71193a33cd033ae9ddcee1db3df07e    refs/heads/master
$ git remote show origin
* remote origin
  Fetch URL: ssh://[host]//tmp/tt.git/
  Push  URL: ssh://[host]//tmp/tt.git/
  HEAD branch: master
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (fast-forwardable)

(ここHEAD branchに示されているのは推測であり、通常は無視する必要があります。HEADすべての の SHA-1 に対して の SHA -1 を照合することによって計算されrefs/heads/*ます。正確に 1 つの一致がある場合にのみ正しいことが保証されます。2 つまたはより多くの一致がある場合、誤って正しい可能性がありますが、これを確実に機能させるには、git でプロトコルを変更する必要があります。)

URL はそれぞれ fromgit config --get remote.origin.urlおよびgit config --get remote.origin.pushurlです (何も設定されていない場合、デフォルトのプッシュ URL はフェッチ URL と同じです)。

では、その理由を見てみましょうmaster merges with remote master。これは、次の 2 つの構成項目によるものです。

$ git config --get branch.master.remote
origin
$ git config --get branch.master.merge
refs/heads/master

(後者の設定には、おそらく歴史的な事故である、いくつかの深い奇妙さがあります。git merge のドキュメントを読むと、次のように表示されます。

branch.<current branch>.mergeによって名前が付けられたリモートのブランチの名前の値branch.<current branch>.remoteが参照され、対応するリモート追跡ブランチにマップされremote.<remote>.fetch、これらの追跡ブランチのヒントがマージされます。

「正常な」構成では (git fetch以下の注を参照)、これはrefs/heads/master上記が実際に意味することを意味しrefs/remotes/origin/masterます。)

また、master pushes to masterこの特定のケースでgit config push.default matchingは、このリポジトリに設定したため、push.default. 新しいバージョンの git を使用している場合、および/または を設定push.defaultしていない場合、または別の方法で設定している場合は、別のバージョンにプッシュされる可能性があります。現在可能な値はnothingcurrentupstreamsimpleおよびmatchingです。git-config のドキュメントを参照してください。

ここで、このプッシュが早送りである理由について説明します。ls-remote出力から、リモートrefs/heads/master(つまり、masterプッシュ先) が参照していることがわかります120a630b0b71193a33cd033ae9ddcee1db3df07e。すでにご存じのように (おそらく気付いていないかもしれませんが)、私たちが持っていて、彼らが持っていないものを見ることができます:

$ git rev-list 120a630b0b71193a33cd033ae9ddcee1db3df07e..master
eed7b697cab0cbd5babf382f720668e12a86cf2a
224384fed46e1949c88eb514fa67743be66a4c5a
ddc0aab680bab0bd6a7dde4a6ef8cb58ba0368e6
ade842c8562cdccd1e98f7ffd5149a12ddc9226c

4 つのコミットがありますが、そうではありません。そして、git fetchこれらすべてを開始する前に実行し、適切な構成を持っているため、私たちが持っていないものを確認できます。

$ git rev-list master..120a630b0b71193a33cd033ae9ddcee1db3df07e

それは何もありません。もう 1 つ知っておく必要があります。実際、これから始めるべきです。つまり、「120a630...実際にはmaster( ade842c...) の祖先ですか、そうでない場合は、それと私たちの間に共通の祖先がありますmasterか?」ということです。ここでは、省略形の SHA-1 と名前masterを長さとして使用します。

$ if git merge-base --is-ancestor 120a630 master; then echo OK; fi
OK

—したがって、これは「早送り可能」です。つまり、4 より進んで 0 より遅れています。(実際、先祖であることは、遅れていないことを直ちに意味します。の出力ls-remote。)

120a630が の祖先でない場合master、それは 2 つのことのいずれかを意味します。たぶん、私たちのmasterは彼らmasterの . または、おそらくより可能性が高いのは、それらが私たちのすぐ前にある (早送りできる) か、次のようなコミット グラフ フラグメントを持つ共通の祖先がある場合です。

        D--E--F
       /
A--B--C
       \
        G--H

(たとえば、Cは共通の祖先であり、それらは にFあり、私たちは にあり、リベースまたはマージできます)。H

それを見つけるには、彼らmasterと逆方向に作業を開始し、私たちmasterと逆方向に作業を開始して、それらがある時点で一致するかどうかを確認する必要があります。willを使用git merge-baseしてポイントを見つけることができますが、これはmastercommit-IDだけでなく、そのポイントまでFの中間 ID (Dと) も必要であることを意味します。Eこれもまた、する必要があることを意味しgit fetchます。

を実行するgit fetchと、それらrefs/heads/masterが にある120a630b0b71193a33cd033ae9ddcee1db3df07eことを検出するだけでなく、必要なコミット (ない場合もあれば、多くの場合もあります) も取得されますgit rev-list

を使用すると git 参照も set にgit fetch更新されます。しかし、それは次の理由だけです。refs/remotes/origin/master

$ git config --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*

この構成項目はfetch、参照のリストを取得した後 (同じものがls-remote出力されます)、一致するものを取得しrefs/heads/*、名前を に変更し、refs/remotes/origin/<match>それらをローカルリポジトリに詰め込む必要があることを示しています。

これは変更できるため、更新されgit fetchませorigin/master。誰かがそれを行った場合、git rev-list origin/master..master役に立ちません。D(そして、コミット、E、およびいずれかを取得できるかどうかはわかりませんF! クレイジーなフェッチ構成で実行したことはありません。)

要約すると、次のことを理解する必要があります。

  • 接続するリモート (ある場合)
  • これらのリモートに対応するローカル ブランチ ( refs/heads/*) (プルおよび/またはプッシュ)
  • 彼らの支部長が私たちの支部長と関係があるかどうか (同じ名前か別の名前か)
  • matchingプッシュが同じ名前 ( , current, simple-if-name-same ) にプッシュされるか、潜在的に別の名前 ( upstream) にプッシュされるか、「決して」プッシュされないか ( nothing, simple-if-name-different )
  • 一部またはすべてのリモートに接続しないことを選択した場合に、参照を信頼するかどうかrefs/remotes/(行に基づく)remote.name.fetch

pushfetchが非対称であるため、すべて非常に面倒です。git push blargがプッシュされる可能性がありますmatching(したがって、blargという名前のブランチがある場合、セットがなくても、そこにglinkプッシュします)。構成変数、などもあります。その他の構成も同様です (再度、git-config のドキュメントを参照してください)。glinkglinkbranch.glink.remoteremote.pushdefaultremote.name.pushfetch

git fetch( を実行してから、おそらく を使用するのが最善だと思いますgit branch -vv。)

于 2013-10-11T18:35:47.750 に答える