web-dev-qa-db-ja.com

Git-2つのリモートのタグ名が同じ場合、リモートタグをチェックアウトします

私はこれがうまくいくと思っていました:

git checkout remote/tag_name

しかし、そうではありません。これは:

git checkout tags/tag_name

しかし、私は多くのリモコンがあるところで奇妙なことをしていて、2つのリモコンが同じタグを持っているとどうなるか心配です。タグをチェックアウトするときにリモートを指定する方法はありますか?

46
Narfanator

エグゼクティブサマリー:達成したいことは可能ですが、最初にリモートタグを作成する必要があります。

これを行うには、リモートごとに1つずつ、一連​​のrefspecを使用します。これ以降は、これらが何であるか、どのように機能するかなどについてです。


あなたの質問は「リモートタグ」のチェックアウトについて尋ねますが、Gitはリモートタグをhaveしません。

しかし、私はたくさんのリモコンがあるところで奇妙なことをしていて、2つのリモコンが同じタグを持っているとどうなるか心配です。タグをチェックアウトするときにリモートを指定する方法はありますか?

あなたの混乱の原因を明らかにします。

ちょっと戻って、Gitが一般的な意味で持っているもの、つまり「参照」について話しましょう。アイデアを固めるために、特定のformsにはローカルブランチ名(masterdevelfeatureなど)、Origin/masterstuff_from_bobs_computer/masterなどの「リモートブランチ名」、およびタグ名が含まれます。 Gitの「スタッシュ」のようなものも参照を使用します。HEADさえも参照ですが、非常に特別なものであり、通常は「シンボリック」参照です。ここでのポイントは、Gitには多くの参照形式があり、最終的にはすべて同じように機能するということです。参照名は、最終的に、これらの大きなSHA-1値、676699a0e0cdfd97521f3524c763222f1c30a094などのいずれかに解決されます。

ほとんどの参照(例外はHEADORIG_HEADMERGE_HEAD、およびこれらの行に沿った他のいくつか)は、実際にはrefs/で始まる名前で綴られています。これらは、一種のディレクトリまたはフォルダのような構造に保持され、1 サブディレクトリあり:refs/tags/にはタグが含まれ、2 refs/heads/にはすべてのブランチが含まれ、refs/remotes/にはすべてのリモートブランチが含まれます。

リモートブランチは、リモートの名前によってさらに細分化されます。refs/remotes/Origin/には、すべてのOriginリモートブランチが含まれますが、refs/remotes/stuff_from_bobs_computer/には、すべてのstuff_from_bobs_computerリモートブランチが含まれます。多数のリモートがある場合、refs/remotes/内に多数のサブディレクトリがあります。

あなたのタグはすべてrefs/tags/にあると言ったばかりです。リモートのタグについてはどうですか、すべてのさまざまなリモートのすべてのタグはどうですか?繰り返しますが、gitには「リモートタグ」はありません。 Gitには「リモートブランチ」がありますが、実際にはそれらはすべてローカルにあります。これらはrefs/remotes/見出しの下のyourリポジトリに保存されます。

Gitが「リモート」にアクセスすると、通常はgit fetch remoteを介しますが、Push(および最初のcloneステップも)を通じて、yourGitはリモートGitに問い合わせます3 質問:「ローカルブランチは何ですか?SHA-1の値は何ですか?」これは、実際、fetchの仕組みです。簡単な説明として、フェッチのプロセスは、リモートGitに「ねえ、whaddayaを手に入れましたか?」また、一連の名前とSHA-1を提供します。 Gitは、同じSHA-1を持っているかどうかを確認します。もしそうなら、会話は完了です。そうでない場合、Gitは「OK、これらのSHA-1のコミットに何でも必要です」と言います。これは実際にはSHA-1の別の束であることがわかり、GitとそのGitと彼らが話し合います必要なファイルなどもすべてSHA-1で識別されます。 Gitはこれらのオブジェクトを持ち込み、新しいSHA-1をリモートの名前で、次にローカルのブランチ名でrefs/remotes/に詰め込みます。

fetchを使用してタグを要求すると、Gitはもう少し処理を行います。4 ブランチについてGitに質問するだけでなく、Gitはタグについても彼らに尋ねます。繰り返しますが、彼らのGitは名前とSHA-1のリストを提供するだけです。次に、Gitが必要な基礎となるオブジェクトをもたらします。次に、これが問題全体の鍵となります。それは、タグ名をrefs/tags/.に書き込みます

したがって、リモートのOriginに移動してタグを要求すると、「refs/tags/pinkyrefs/tags/brainがあります」と表示されると、参照用にrefs/tags/pinkyrefs/tags/brainという名前のローカルタグpinkybrainが作成されます名前空間。

次に、ボブのコンピューター(上記のstuff_from_bobs_computerという名前のリモート)に移動して、タグを要求します。彼はワーナーブラザーズアンドシスターではなく神経学に興味があり、彼のタグはrefs/tags/spinal_cordrefs/tags/brainであり、2番目のタグはおそらくOriginのタグとは関係ありません。ええとああ!

ここで何が起こるかは少し複雑になりますが、5 しかし、要するに、これはただの悪い状況であり、可能であればおそらく避けるべきです。それを避けるための2つの簡単な(まあ...)方法があります。 1つは明らかな欠点ですが、タグを取得しないでください。そうすれば、タグの競合は発生しません。もう1つは、すべてのタグを互いに分離した状態に保つことです(おそらく、あなたのタグからも分離します)。 2番目のものはそれほど難しくないことがわかります。リモートタグを「発明」するだけです。

Gitが実際に「リモートブランチ」を実装する方法と、fetch --tagsがどのように機能するかを簡単に見てみましょう。どちらもgitが「refspecs」と呼ぶ同じ基本メカニズムを使用します。

最も単純な形式では、refspecはコロンで区切られた2つのref名のように見えます。たとえば、refs/heads/master:refs/heads/masterです。実際、refs/heads/を省略することもできます。Gitはそれを自動的に配置します。6 場合によっては、コロンと同じ名前を省略することもできます。これは、git Pushで使用する種類です。git Push Origin branchは、refs/heads/branchを使用してOriginにプッシュし、 "their" Gitに到着したときにrefs/heads/branchを呼び出すことを意味します。

ただし、fetchの場合、リモートブランチを実行すると、次のようなrefspecが取得されます。

+refs/heads/*:refs/remotes/Origin/*

先頭の+は「力」を意味し、*sは明白なことを行います。あなたのGitは彼らと話をし、refのリストを取得します。 refs/heads/*に一致するものは、(必要に応じてリポジトリオブジェクトとともに)持ち込みますが、その後、refs/remotes/Origin/で始まる名前の下にyourリポジトリにそれらを貼り付け、すべての「リモートOriginから分岐します。7

git fetch --tagsを実行すると、gitは使用するrefspecに+refs/tags/*:refs/tags/*を追加します。8 これにより、タグが表示され、ローカルタグに配置されます。したがって、あなたがしなければならないのは、fetchに次のようなrefspecを与えることです:

+refs/tags/*:refs/rtags/Origin/*

突然、refs/rtags/の下に「リモートタグ」のまったく新しい名前空間ができます(この場合はOriginのみ)。タグのコピーを更新しているだけなので、ここで+ force-flagを使用しても安全です。タグを強制的に移動(または削除して再作成)した場合は、コピーを強制的に移動します。また、コマンドラインで--no-tagsを指定することで取得できる--no-tagsの動作が必要な場合や必要になる場合もあります。次の段落を参照してください。

知っておくべき唯一の便利な項目は、git fetchがGit構成ファイルから特定のリモートのデフォルトのrefspecsを取得することです。9 Git構成ファイルを調べると、fetch =文字列を使用して、各リモートの下に+refs/heads/*:refs/remotes/remote-name/*行が表示されます。リモートごとに好きなだけfetch =行を追加できるため、タグを追加するために1行を追加できますが、新しく(再)発明された「リモートタグ」名前空間にそれらを配置できます。この同じセクションで--no-tagsを設定して、このリモートのtagOpt = --no-tagsをデフォルトにすることもできます。 ser200783によるこのコメント を参照してください。

名前を未加工のSHA-1に解決するすべてのGitコマンドと同様に、完全な参照名でgit checkoutを実行して、対応するSHA-1で「デタッチされたHEAD」モードにすることができます。

git checkout refs/rtag/stuff_from_bobs_computer/spinal_cord

Gitには「リモートタグ」という概念が組み込まれていないため、長い形式を詳しく説明する必要があります(詳細については gitrevisions を参照してください)。


1実際、.git/refs内の実際のディレクトリです。ただし、参照用の「パック」フォームもあり、それは.git/packed-refsになります。パックされたフォームは、頻繁に変更されない(またはタグで一般的な)refで時間と労力を節約するためのものです。また、参照用に「バックエンド」ストレージシステムを書き直す努力も継続されているため、ある時点でこの多くが変更される可能性があります。この変更は、WindowsおよびMacシステムに必要です。 Gitでは、ブランチ名とタグ名では大文字と小文字が区別されると考えています。シューシャイン素材にはpolishを、ソーセージにはPolishを使用できます。パックバージョンは大文字と小文字が区別されるため、したがって、これは機能します。しかし、ファイルに保存されたバージョンは時々しないので、そうではありません!

2ここでは、軽量タグと注釈付きタグの違いについて説明します。注釈付きタグはリポジトリ内の実際のオブジェクトですが、軽量タグはrefs/tags/スペース内のラベルです。ただし、一般的に、各注釈付きタグには対応する軽量タグが1つあるため、この特定の使用法では同じように機能します。

3ほとんどの場合、別のGitレポジトリですが、GitからMercurial、svnなどへのアダプタがあります。 Gitリポジトリのふりをするための独自のトリックがあります。また、この説明は決定的なものではありません。操作の実際のシーケンスは、人間に理解させるためではなく、転送効率のためにコーディングされています。

4ここでは、プレーンなfetchcloneについて、つまり--tagsを使用しないバージョンについて、少し特別な奇妙さを説明しました。バージョンwith--tagsは説明が簡単です。ここで説明したrefspecを使用してすべてのタグを提供します。少なくともGit 2.10および2.11では、--tagsも強制更新を行います。 + forceフラグが設定されているかのように。ただし、--no-tagsを明示的に呼び出さない限り、プレーンフェッチ(およびクローン)はsomeタグをもたらします。それが行う卑劣なことは、フェッチによって入ってくるオブジェクトに対応するタグを探し、それらを(更新を強制せずに)(グローバル)タグの名前空間に追加することです。 --tagsがなければ、Gitは既存のタグを上書きしません。 --tagsを使用すると、Gitwillは、2017年初頭に実行された実際の実験ごとに、少なくともGit 2.10では既存のタグを上書きします。

5Gitの以前のバージョンは、Pushの間にタグに「ブランチ」ルールを適用しました(ただし、必ずしもフェッチする必要はありません)。 git Pushの新しいバージョンでは、forceタグのみが必要です。 --tagsからのfetchrefspecには、強制フラグが設定されていませんが、機能するように動作します。 --tagsを使用したプッシュの実験は行っていません。 git fetch--tags対明示的なrefspecには、--no-tagsの動作に関係する特別な--Pruneの奇妙な点がもう1つあります。ドキュメントでは、--Pruneは明示的なコマンドラインrefs/tags/ refspecに適用されますが、暗黙的な--tags refspecには適用されません。これを検証するための実験も行っていません。

6Gitがrefs/heads/またはrefs/tags/を入力するためには、Gitが意図したものをfigure outできる必要があります。ある場合とそうでない場合があります。 Gitがそれを理解できなかった場合、エラーメッセージが表示され、それを埋めて再試行できますが、スクリプトでは、より予測可能な動作を得るために、常に明示的に入力する必要があります。 git Pushを実行して既存のブランチをプッシュする場合は、ほとんどいつでもGitにそれを理解させることができます。

7コロンと2番目の名前を省くと、git fetchでうまく機能しません。Gitに、独自の参照をまったく更新しないように指示します。これは無意味に思えますが、git fetchalwaysが特殊ファイルFETCH_HEADを書き込むため、実際にはcanが役立ちます。 GitオブジェクトID(SHA-1)を特殊ファイルから取り出して、何が取得されたかを確認できます。これは、リモートトラッキングブランチが発明される前の、Gitの非常に初期のバージョンからのホールドオーバーです。

8git fetch --tagsおよびgit Push --tagsが使用するrefspecは、Gitバージョン2.10で内部的にプリコンパイルされ、特別なケースコードによって処理されます。プリコンパイルされたフォームには+フラグが設定されていません。しかし、実験により、フェッチされたタグはGit 2.10/2.11で強制的に更新されることが示されています。何年も前にGit 1.xで実験し、これらの--tags- fetchedタグがnot強制更新されたことを思い出したので、これは変更されたと思いますが、それは単なる欠陥のあるメモリかもしれません。いずれにせよ、リモートタグを(再)発明している場合は、おそらく明示的に--tagsを使用したいnotを行うでしょう。

9実際、これがミラーの仕組みです。たとえば、fetch = +*:*を使用すると、純粋なフェッチミラーが取得されます。フェッチプロセスでは、すべての参照を確認できます。 git ls-remoteを使用して自分で確認できます。また、--single-branchの動作方法も同じです。クローン中に--single-branchを使用すると、Gitの構成ファイルにはフェッチ行に1つのブランチのみがリストされます。単一ブランチから全ブランチに変換するには、通常のglob-patternエントリを含むように行を編集するだけです。

76
torek

1-リモートでタグを取得します:

git fetch Origin --tags 

または、別のリモート使用からタグをチェックアウトするには:

git fetch your_remote --tags

2実行してタグをチェックアウトします

git checkout tags/<tag_name>

詳細: Gitで特定のタグをダウンロード

82
Russell Fair

私の場合、新しいリポジトリがリモートリポジトリに追加されたとき[私はStashを使用しています]、新しいタグはgit tag -lの結果で利用できませんでした。
しかし、git ls-remote --tagsを使用して、新しく追加されたタグを表示できました。
次のコマンドを実行して、すべての最新のタグをローカルリポジトリに取得する必要がありました。
git pull --tags実行中git tag -lは、新しく追加されたタグも表示するようになりました。

タグをチェックアウトするには、次を使用します。
git checkout <tag_name>

注:git statusを実行し、次のようなメッセージを見つけるのは正常なことです。
HEAD detached at tag_name

9
hipsandy

私の心にはいくつかの質問があります:

  • (同じツリー内で)異なるリモートに異なるコードが必要なのはなぜですか?
  • リモートコードがタグのチェックアウトに影響するのはなぜですか?

事は次のとおりです。

git checkout tags/fancytagを使用してタグをチェックアウトすると、(マシン上の)現在のリポジトリで適切なタグが検索されます。

特定のリモートからタグをチェックアウトする場合は、最初にfetchそれ(特定のリモートのツリー)をチェックアウトする必要があります。

0