Como posso mover uma marca em um ramo git para um commit diferente?

858

Eu criei uma tag no ramo mestre chamada v0.1assim:

git tag -a v0.1

Mas então eu percebi que ainda havia algumas mudanças que eu precisava mesclar no master para a versão 0.1, então eu fiz isso. Mas agora minha v0.1tag está presa (para invocar a analogia do post-it note) no commit errado. Eu quero que ele fique preso no commit mais recente no master, mas em vez disso, ele estará preso no segundo commit mais recente no master.

Como posso movê-lo para o commit mais recente no mestre?

eedeep
fonte

Respostas:

1200

Use a -fopção para git tag:

-f
--force

    Replace an existing tag with the given name (instead of failing)

Você provavelmente deseja usar -fem conjunto com -apara forçar a criação de uma marca anotada em vez de uma marca não anotada.

Exemplo

  1. Exclua a tag em qualquer controle remoto antes de pressionar

    git push origin :refs/tags/<tagname>
    
  2. Substitua a tag para referenciar a confirmação mais recente

    git tag -fa <tagname>
    
  3. Envie a etiqueta para a origem remota

    git push origin master --tags
    
Greg Hewgill
fonte
90
Pode ser uma boa idéia excluir a tag em qualquer controle remoto antes de você pressionar também, fazendo o seguinte: git push origin :refs/tag/<tagname>e então faça git tag -fa <tagname>e depois git push origin master --tags. Caso contrário, você poderá terminar com coisas estranhas na lista de referências no controle remoto, com ^ e {} caracteres sendo anexados. Agradecemos a Dan no codebasehq.com por apontar isso.
eedeep
47
@eedeep: Correção menor - em vez :refs/tag/<tagname>disso deveria ser :refs/tags/<tagname>.
Ben Hocking
8
Isso funciona apenas se você não tiver enviado o código da sua máquina. Se você tiver, a melhor resposta é 'há muitos números no mundo', pois provavelmente não vale a pena.
precisa
33
Se você já tinha empurrado sua tag você ainda pode atualizar a tag remoto com um empurrão forçadogit push -f origin <tagname>
rc_luke
11
O que não é mencionado aqui e nos documentos é que isso realmente move a mensagem de marca, se nenhuma nova mensagem for fornecida.
Twonky
259

Mais precisamente, você deve forçar a adição da tag e pressionar com a opção --tags e -f:

git tag -f -a <tagname>
git push -f --tags
Daniel
fonte
171

Para resumir se o seu controle remoto é chamado origine você está trabalhando na masterramificação:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • A linha 1 remove a tag no ambiente local.
  • A linha 2 remove a etiqueta no ambiente remoto.
  • A linha 3 adiciona a tag a confirmação diferente
  • A linha 4 envia a alteração para o controle remoto

Você também pode trocar a linha 4 para git push origin --tagsenviar todas as alterações com tags das alterações locais.

Baseando-se nas respostas @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking, comentários abaixo de suas respostas e comentários NateS abaixo de minha resposta.

Vive
fonte
87

Exclua-o git tag -d <tagname>e recrie-o na confirmação correta.

Stuart Golodetz
fonte
3
@eedeep: Acho que a resposta de Greg é realmente melhor aqui para ser justa.
Stuart Golodetz 8/11
Mantenha simples. Exclua, faça o que você fez antes novamente.
ooolala
1
Essa deve ser a resposta aceita, por sua simplicidade. Também não usa -f force excessivamente.
Chinnychinchin
48

Eu tento evitar algumas coisas ao usar o Git.

  1. Usando o conhecimento dos internos, por exemplo, refs / tags. Tento usar apenas os comandos Git documentados e evito usar coisas que exijam conhecimento do conteúdo interno do diretório .git. (Ou seja, trato o Git como um usuário do Git e não como desenvolvedor do Git.)

  2. O uso da força quando não é necessário.

  3. Exagerando nas coisas. (Empurrando um ramo e / ou muitas tags, para obter uma tag onde eu quiser.)

Então, aqui está minha solução não violenta para alterar uma tag, local e remotamente, sem o conhecimento dos componentes internos do Git.

Eu o uso quando uma correção de software apresenta um problema e precisa ser atualizada / relançada.

git tag -d fix123                # delete the old local tag
git push github :fix123          # delete the old remote tag (use for each affected remote)
git tag fix123 790a621265        # create a new local tag
git push github fix123           # push new tag to remote    (use for each affected remote)

githubé um nome remoto de amostra, fix123é um nome de marca de amostra e 790a621265uma confirmação de amostra.

Ivan
fonte
26

Vou deixar aqui apenas outra forma deste comando que atendeu às minhas necessidades.
Havia uma etiqueta v0.0.1.2que eu queria mover.

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

E depois:

$ git push --tags --force
Nakilon
fonte
bom, obrigado, 2 comandos simples e simples
Sérgio
10

Uma outra maneira:

Mova a tag no repositório remoto (substitua HEAD por qualquer outro, se necessário).

$ git push --force origin HEAD:refs/tags/v0.0.1.2

Buscar alterações de volta.

$ git fetch --tags
Алексей Югов
fonte
Isso é mais "transacional" do que as outras respostas.
Justin M. Keyes
9

Alias ​​para mover uma tag para uma confirmação diferente.

Na sua amostra, para mover a consolidação com o hash e2ea1639, faça: git tagm v0.1 e2ea1639 .

Para tags enviadas, use git tagmp v0.1 e2ea1639 .

O alias mantém a data e a mensagem originais. Se você usargit tag -d você perdeu sua mensagem original.

Salve-os em seu .gitconfigarquivo

# Return date of tag. (To use in another alias)
tag-date = "!git show $1 | awk '{ if ($1 == \"Date:\") { print substr($0, index($0,$3)) }}' | tail -2 | head -1 #"

# Show tag message
tag-message = "!git show $1 | awk -v capture=0 '{ if(capture) message=message\"\\n\"$0}; BEGIN {message=\"\"}; { if ($1 == \"Date:\" && length(message)==0 ) {capture=1}; if ($1 == \"commit\" ) {capture=0}  }; END { print message }' | sed '$ d' | cat -s #"

### Move tag. Use: git tagm <tagname> <newcommit> 
tagm = "!GIT_TAG_MESSAGE=$(git tag-message $1) && GIT_COMMITTER_DATE=$(git tag-date $1) && git tag-message $1 && git tag -d $1 && git tag -a $1 $2 -m \"$GIT_TAG_MESSAGE\" #"

### Move pushed tag. Use: git tagmp <tagname> <newcommit> 
tagmp = "!git tagm $1 $2 && git push --delete origin $1 && git push origin $1 #"
Juan Antonio Tubío
fonte
1

Se você deseja mover uma tag anotada, alterando apenas a confirmação direcionada, mas preservando a mensagem de anotação e outros metadados, use:

moveTag() {
  local tagName=$1
  # Support passing branch/tag names (not just full commit hashes)
  local newTarget=$(git rev-parse $2^{commit})

  git cat-file -p refs/tags/$tagName | 
    sed "1 s/^object .*$/object $newTarget/g" | 
    git hash-object -w --stdin -t tag | 
    xargs -I {} git update-ref refs/tags/$tagName {}
}

use: moveTag <tag-to-move> <target>

A função acima foi desenvolvida referenciando teerapap / git-move-annotated-tag.sh .

vossad01
fonte
1
Parece que isso não é mais necessário: git tag -f -a my_tagjá preserva a mensagem de uma mensagem anterior (com a versão 2.11.0 do git).
Matthijs Kooijman