Erro "tag já existe no controle remoto" após recriar a tag git


142

Eu recebo o seguinte erro depois de executar as etapas abaixo:

To git@provider.com:username/repo-name.git
 ! [rejected]        dev -> dev (already exists)
error: failed to push some refs to 'git@provider.com:username/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.
  1. Criou o repositório
  2. Clonou o repositório na máquina local.
  3. Modificou o arquivo README, confirmou as alterações e enviou o commit por push.
  4. Tag criada dev:git tag dev
  5. Tags enviadas: git push --tags
  6. Modificou o arquivo README, confirmou as alterações e enviou o commit por push.
  7. Tag excluída dev, criada novamente e enviada por push:

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

Por que isso está acontecendo?

Estou no Mac. Meus amigos que usam Linux (Ubuntu) não têm esse problema. Eu sei que posso usar git push --tags -fpara forçar a atualização da tag, mas isso é perigoso (por exemplo, reescrever uma confirmação feita por engano apenas na tag, não na ramificação).


1
As confirmações não são feitas "em tags" ou "em branches" (embora pareça que o último é o caso). De fato, os nomes de tags e ramificações simplesmente apontam para (um, único) commit. Veja a resposta abaixo.
Torek

8
isso funcionou para mim, git pull --tagsentãogit push origin --tags
sawe

Respostas:


175

Edit, 24 Nov 2016: esta resposta é aparentemente popular, por isso estou adicionando uma nota aqui. Se você substituir uma marca em um servidor central, qualquer pessoa que possua a marca antiga - qualquer clone do repositório do servidor central que já tenha a marca - poderá reter sua marca antiga . Portanto, embora isso lhe diga como fazê-lo, tenha certeza de que deseja fazê-lo. Você precisará solicitar a todos que já possuem a tag "errada" para excluir a "tag errada" e substituí-la pela nova "tag correta".

Testar no Git 2.10 / 2.11 mostra que manter a tag antiga é o comportamento padrão para clientes em execução git fetch, e atualizar é o comportamento padrão para clientes em execução git fetch --tags.

(A resposta original segue.)


Quando você pede para enviar tags por envio, git push --tagsenvia (juntamente com quaisquer confirmações e outros objetos necessários e quaisquer outras atualizações de referência das configurações de envio) para o remoto uma solicitação de atualização do formulário . (Bem, ele envia muitos: um desses para cada tag.)new-sha1 refs/tags/name

A solicitação de atualização é modificada pelo controle remoto para adicionar um old-sha1(ou novamente, um para cada tag) e depois entregue aos ganchos de pré-recebimento e / ou atualização (os ganchos existentes no controle remoto). Esses ganchos podem decidir se permitem ou rejeitam a tag create / delete / update.

O old-sha1valor é o SHA-1 "nulo" com todos os zeros se a tag estiver sendo criada. O new-sha1é o SHA-1 nulo se a tag estiver sendo excluída. Caso contrário, os dois valores SHA-1 são reais e válidos.

Mesmo sem ganchos, existe um tipo de "gancho embutido" que também é executado: o controle remoto se recusará a mover uma tag, a menos que você use o sinalizador "force" (embora o "gancho embutido" esteja sempre bem com os dois "adicionar" e "excluir"). A mensagem de rejeição que você vê é proveniente desse gancho embutido. (Aliás, esse mesmo gancho embutido também rejeita atualizações de ramificações que não são rápidas). 1

Mas - eis uma das chaves para entender o que está acontecendo - a git pushetapa não faz ideia se o controle remoto tem essa tag agora e, se sim, qual o valor do SHA-1. Diz apenas "aqui está minha lista completa de tags, junto com seus valores SHA-1". O controle remoto compara os valores e, se houver adições e / ou alterações, os ganchos serão executados. (Para tags iguais, não faz absolutamente nada. Para tags que você não possui, elas também não fazem nada!)

Se você excluir a tag localmente push, seu envio simplesmente não transferirá a tag. O controle remoto pressupõe que nenhuma alteração deve ser feita.

Se você excluir a tag localmente, crie-a apontando para um novo local, pushseu push transferirá a tag e o controle remoto verá isso como uma alteração de tag e rejeitará a alteração, a menos que seja um push forçado.

Assim, você tem duas opções:

  • fazer um empurrão forçado, ou
  • exclua a tag no controle remoto.

O último é possível via git push2, mesmo que a exclusão local da tag e o pushing não tenham efeito. Supondo que o nome do controle remoto seja origine a tag que você deseja excluir seja dev:

git push origin :refs/tags/dev

Isso pede ao controle remoto para excluir a tag. A presença ou ausência da tag devno seu repositório local é irrelevante; esse tipo de push, como refspec, é um push de exclusão pura.:remoteref

O controle remoto pode ou não permitir a exclusão de tags (dependendo dos ganchos extras adicionados). Se permitir a exclusão, a tag desaparecerá e, um segundo git push --tags, quando você tiver uma devtag local apontando para algum objeto de repo de tag de confirmação ou anotação, envie sua nova devtag. No controle remoto, devagora será uma tag recém-criada; portanto, o controle remoto provavelmente permitirá o envio (novamente isso depende de quaisquer ganchos extras adicionados).

O empurrão forçado é mais simples. Se você quiser ter certeza de não atualização qualquer outro do que a tag, basta dizer git pushpara empurrar apenas que uma refspec:

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

(observação: você não precisa --tagsse estiver pressionando explicitamente apenas uma tag ref-spec).


1 Obviamente, o motivo desse gancho interno é ajudar a reforçar o comportamento que outros usuários do mesmo repositório remoto esperam: que ramos não sejam rebobinados e que as tags não sejam movidas. Se você forçar, deve informar os outros usuários que você está fazendo isso, para que eles possam corrigi-lo. Observe que "as tags não se movem" são aplicadas recentemente pelo Git 1.8.2; versões anteriores permitiriam que a tag "avançasse" no gráfico de confirmação, como os nomes das ramificações. Veja as notas de lançamento do git 1.8.2 .

2 É trivial se você puder fazer login no controle remoto. Basta ir ao repositório Git lá e executar git tag -d dev. Observe que, de qualquer maneira - excluindo a tag no controle remoto ou usando-a git pushpara excluí-la -, há um período em que qualquer pessoa que acessa o controle remoto descobre que a devtag está ausente. (Eles continuarão a ter sua própria tag antiga, se já a tiverem, e podem até empurrar a tag antiga de volta antes que você possa empurrar a nova.)


Isso está acontecendo apenas nas novas versões do git? Eu tenho 1.7.9.5e eu não tenho esse problema ...
Ionică Bizau

2
Probalby - tenho uma vaga memória de git push --tagsapenas alterar a tag automaticamente em versões mais antigas do git, sem --force. Eu testei isso no 1.8.4, e você precisa --force, ou a técnica de atualização em dois estágios.
Torek

2
@ John ツ: update: é um novo comportamento a partir do 1.8.2, de acordo com as notas da versão . Também vou editar isso na nota de rodapé 1.
Torek # 10/13

Não sei como entrei nessa situação, mas essa tag foi excluída e recriada rapidamente.
RiggsFolly

4
como você faz um empurrão forçado se você não é um jedi?
Fonix

54

No Mac SourceTree, desmarque apenas a caixa de seleção Enviar todas as tags :

insira a descrição da imagem aqui


3
hahahah cara tão simples, eu estava lendo a resposta aceita e pensei que eu iria fingir isso
MegaManX 13/16

10
Isso é apenas para superá-lo sem realmente resolver o problema. Isso não resolve o nome da marca como falta de correspondência em local e remoto.
amalBit

1
funciona para a versão do Windows também! obrigado por nos salvar de ler a resposta a longo aceita que omite sourcetree usuários que não se importam o que está acontecendo no prompt de comando :)
Schlingel

19

É bem simples se você estiver usando o SourceTree .

insira a descrição da imagem aqui Basicamente, você só precisa remover e adicionar novamente a tag conflitante:

  1. Vá para a guia Repositório -> Tag -> Remover Tag
  2. Selecione o nome da tag conflitante
  3. Marque Remover etiqueta de todos os controles remotos
  4. Pressione Remover
  5. Crie uma nova tag com o mesmo nome para o commit apropriado
  6. Certifique-se de verificar Enviar todas as tags ao enviar suas alterações para controle remoto

16

Se você deseja atualizar uma tag, digamos que1.0.0

  1. git checkout 1.0.0
  2. faça suas alterações
  3. git ci -am 'modify some content'
  4. git tag -f 1.0.0
  5. excluir tag remota no github: git push origin --delete 1.0.0
  6. git push origin 1.0.0

FEITO


12

Parece que estou atrasado e / ou já foi respondido, mas o que poderia ser feito é: (no meu caso, eu tinha apenas uma tag localmente, excluí-a e a retirei com :

git tag -d v1.0
git tag -a v1.0 -m "My commit message"

Então:

git push --tags -f

Isso atualizará todas as tags no controle remoto.

Pode ser perigoso! Use por sua conta e risco.


1
Isso fez por mim! As marcas eram apenas localmente e não no remoto :)
pgarciacamou

4

O motivo pelo qual você está sendo rejeitado é que sua tag perdeu a sincronização com a versão remota. Esse é o mesmo comportamento com ramificações.

sincronizar com a tag do controle remoto via git pull --rebase <repo_url> +refs/tags/<TAG>e após a sincronização, você precisa gerenciar conflitos . Se você tiver um diftool instalado (por exemplo, meld), git mergetool melduse-o para sincronizar remotamente e manter suas alterações.

O motivo pelo qual você está usando o sinalizador --rebase é que deseja colocar seu trabalho em cima do controle remoto para evitar outros conflitos.

Além disso, o que não entendo é por que você excluiria a devtag e a recriaria ??? As tags são usadas para especificar versões ou marcos de software. Exemplo de etiquetas git v0.1dev, v0.0.1alpha, v2.3-cr(cr - libertação candidato) e assim por diante ..


Outra maneira de resolver isso é o problema ae git reflogvá para o momento em que você pressionou a devtag no controle remoto. Copie o ID de confirmação e git reset --mixed <commmit_id_from_reflog>dessa forma você sabe que sua tag estava sincronizada com o controle remoto no momento em que você a pressionou e nenhum conflito surgirá.


Por exemplo, se você deseja marcar uma confirmação que está atualmente em produção. Você precisaria excluir a tag de produção antiga de uma confirmação específica e criar e enviar uma nova tag para a confirmação após o novo release de produção.
Ville Miekk-oja

2

No Windows SourceTree, desmarque Push all tags to remotes .

insira a descrição da imagem aqui


0

Algumas boas respostas aqui. Especialmente o de @torek . Eu pensei em adicionar essa solução alternativa com uma pequena explicação para aqueles com pressa.

Para resumir, o que acontece é que, quando você move uma marca localmente, ela muda de um valor de confirmação não nulo para um valor diferente. No entanto, como o git (como comportamento padrão) não permite a alteração de tags remotas que não sejam nulas, não é possível fazer a alteração por push.

A solução alternativa é excluir a tag (e marque remover todos os controles remotos). Em seguida, crie a mesma tag e pressione.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.