1. ホーム
  2. git

[解決済み] gitタグを再作成した後に "tag already exists in remote "というエラーが発生しました。

2022-04-26 20:25:50

質問

以下のステップを実行すると、以下のエラーが発生します。

To [email protected]:username/repo-name.git
 ! [rejected]        dev -> dev (already exists)
error: failed to push some refs to '[email protected]:username/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.

  1. リポジトリの作成
  2. ローカルマシンにレポをクローン。
  3. READMEファイルを修正し、変更をコミットし、コミットをプッシュしました。
  4. 作成したタグ dev : git tag dev
  5. タグを押しました。 git push --tags
  6. READMEファイルを変更し、その変更をコミットし、コミットをプッシュしました。
  7. 削除されたタグ dev を作成し、再度作成し、タグをプッシュしました。

    git tag -d dev
    git tag dev
    git push --tags
    
    

なぜこのようなことが起こるのでしょうか?

私はMacを使用しています。Linux(Ubuntu)を使っている友人には、この問題はありません。私は、私が使用できることを知っている git push --tags -f を使えば強制的にタグを更新することができますが、これは危険です(例えば、間違って行ったコミットをブランチではなくタグだけ書き換えるなど)。

解決方法は?

2016年11月24日編集:この回答はどうやら人気があるようなので、ここに追記します。 もし、あなたが 置き換える タグを中央のサーバーで使用する場合、そのタグを持っている人は 古い タグ、つまりそのタグをすでに持っているセントラルサーバーリポジトリのクローンは、そのタグを使うことができます。 古いタグを保持する . そのため、この説明ではその方法を説明していますが、実際には 欲しい を実行する必要があります。 すでに "間違った" タグを持っている人全員を削除する必要があります。 その タグを新しいタグに置き換えます。

Git 2.10/2.11 でテストしたところ、古いタグを保持することが git fetch を実行しているクライアントでは更新がデフォルトの動作となります。 git fetch --tags .

(以下、オリジナルの回答)


タグのプッシュを依頼する場合。 git push --tags は (必要なコミットやその他のオブジェクト、そしてプッシュ設定からのその他の ref 更新とともに) リモートに対して次のような形式の更新リクエストを送ります。 new-sha1 refs/tags/name . (まあ、いくつ送ってもいいんですけどね。各タグに1つずつです)。

更新リクエストは、リモートによって修正され old-sha1 (または、各タグに1つずつ)それから pre-receive and/or update フック (リモートに存在するフックのいずれか) に配信されます。 これらのフックは、タグの作成/削除/更新を許可するか拒否するかを決定することができます。

old-sha1 の値は、タグが作成されている場合は、すべてゼロの "null" SHA-1 です。 また new-sha1 は、タグが削除される場合、NULL SHA-1となります。 それ以外の場合は、両方のSHA-1が実際の有効な値です。

フックなしでも、一種の "組み込みフック" が実行されます: リモートは "force" フラグを使用しない限りタグの移動を拒否します ("built-in hook" は "add" と "delete" で常に OK ですが). あなたが見ている拒絶メッセージは、このビルトインフックからきています。 (ちなみに、この同じ組み込みフックは、ファストフォワードでないブランチの更新も拒否します)。 1

しかし、ここで、何が起こっているのかを理解するための鍵のひとつが、この git push ステップでは、リモートが今そのタグを持っているかどうか、持っている場合はどのようなSHA-1値を持っているのか、まったくわかりません。 タグの完全なリストと、そのSHA-1値"とだけ表示されます。 リモートはこの値を比較し、追加や変更があれば、そのタグに対してフックを実行します。 (同じタグの場合、何もしません。 同じタグであっても、自分が持っていないタグは何もしません。)

ローカルでタグを削除した場合 push の場合、プッシュしてもタグが転送されないだけです。 リモートでは、変更が行われるべきではないと判断されます。

もし、ローカルでタグを削除し、新しい場所を指すタグを作成した場合 push そして、リモートはこれをタグの変更とみなし、強制プッシュでない限り、その変更を拒否します。

したがって、2つの選択肢があります。

  • フォースプッシュを行うか
  • リモートのタグを削除する。

後者 を介して可能です。 git push 2 を削除しても、ローカルでタグを削除しても、また push を実行しても何の効果もありません。 リモートの名前が origin で、削除したいタグは dev :

git push origin :refs/tags/dev

これは、タグを削除するようリモートに要求します。 タグの有無は dev は関係ありません。 push を使用した :remoteref を refspec とした場合、純粋な削除プッシュとなります。

リモートはタグの削除を許可するかしないか(追加されたフックに依存します)。 もし削除が可能であれば、そのタグは削除され、2番目の git push --tags がある場合、ローカルで dev タグがコミットや注釈付きタグのリポジトリオブジェクトを指している場合、新しい dev タグを使用します。 リモートでは dev は新しく作成されたタグなので、リモートはおそらくプッシュを許可するでしょう (これも追加されたフックに依存します)。

強制プッシュはよりシンプルです。 もし、何も更新しないことを確認したいのであれば その他 タグよりも git push をプッシュして、その1つの参照仕様だけをプッシュするようにします。

git push --force origin refs/tags/dev:refs/tags/dev

(注意: --tags もし、明示的に一つのタグのref-specをプッシュしているのであれば、そのようなことはありません。)


1 もちろん 理由 この組み込みフックは、同じリモートレポの他のユーザーが期待する動作、つまりブランチを巻き戻さない、タグを移動させないという動作を強制するためのものです。 強制プッシュをする場合は、他のユーザーにそのことを知らせて、修正できるようにする必要があります。 以前のバージョンでは、タグはブランチ名と同じようにコミットグラフの中で "move forward" できましたが、Git 1.8.2 からは "tag doesn't move at all" が新たに適用されたことに注意しましょう。 以前のバージョンでは git 1.8.2リリースノート .

2 リモートでログインできれば些細なことです。 リモートの Git リポジトリに移動し、次のコマンドを実行するだけです。 git tag -d dev . リモートでタグを削除するか、あるいは git push を削除すると、リモートにアクセスした誰もが dev タグがなくなっています。 (彼らは引き続き 自分自身の 古いタグを既に持っている場合は、それを押すかもしれません。 その 新しいタグをプッシュする前に、古いタグをプッシュし直してください)。