Jak mogę przenieść znacznik na gałęzi git do innego zatwierdzenia?

858

W gałęzi master utworzyłem tag o nazwie v0.1tak:

git tag -a v0.1

Ale potem zdałem sobie sprawę, że wciąż muszę wprowadzić pewne zmiany, aby połączyć się w master w wersji 0.1, więc to zrobiłem. Ale teraz mój v0.1tag utknął (aby przywołać analogię karteczek post-it) niewłaściwe zatwierdzenie. Chcę, aby utknęła na ostatnim zatwierdzeniu na master, ale zamiast tego utknęła na drugim ostatnim zatwierdzeniu na master.

Jak mogę przenieść go do ostatniego zatwierdzenia na master?

eedeep
źródło

Odpowiedzi:

1199

Użyj -fopcji, aby git tag:

-f
--force

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

Prawdopodobnie chcesz użyć -fw połączeniu z, -aaby wymusić utworzenie znacznika z adnotacjami zamiast tagu bez adnotacji.

Przykład

  1. Usuń znacznik na dowolnym pilocie przed naciśnięciem przycisku

    git push origin :refs/tags/<tagname>
    
  2. Zamień znacznik, aby odwoływał się do ostatniego zatwierdzenia

    git tag -fa <tagname>
    
  3. Wciśnij znacznik do zdalnego źródła

    git push origin master --tags
    
Greg Hewgill
źródło
90
Dobrym pomysłem może być usunięcie znacznika na dowolnym pilocie przed wypchnięciem, wykonując następujące czynności: git push origin :refs/tag/<tagname>a następnie zrób git tag -fa <tagname>i zrób git push origin master --tags. W przeciwnym razie możesz skończyć z dziwnymi rzeczami na liście ref na pilocie z dołączonymi znakami ^ i {}. Dziękujemy Danowi na codebasehq.com za zwrócenie na to uwagi.
eedeep
47
@eedeep: Drobne poprawki - zamiast :refs/tag/<tagname>tego powinny być :refs/tags/<tagname>.
Ben Hocking
8
Działa to tylko wtedy, gdy nie zepchnąłeś kodu ze swojego komputera. Jeśli tak, najlepszą odpowiedzią jest „na świecie jest mnóstwo liczb”, ponieważ prawdopodobnie nie jest to warte kłopotów.
Chris Huang-Leaver,
33
Jeśli już wypchnąłeś tag, nadal możesz zaktualizować tag zdalny za pomocą wymuszonego pushgit push -f origin <tagname>
rc_luke
11
To, czego nie wspomniano tutaj ani w dokumentach, to fakt, że rzeczywiście powoduje to przeniesienie wiadomości tagu, jeśli nie zostanie podana nowa wiadomość.
Twonky,
259

Mówiąc dokładniej, musisz wymusić dodanie tagu, a następnie nacisnąć opcję --tags i -f:

git tag -f -a <tagname>
git push -f --tags
Daniel
źródło
171

Podsumowując, jeśli Twój pilot jest wywoływany origini pracujesz w masteroddziale:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • Wiersz 1 usuwa tag w lokalnej środowisku.
  • Wiersz 2 usuwa tag w zdalnej env.
  • Wiersz 3 dodaje znacznik do innego zatwierdzenia
  • Linia 4 przekazuje zmianę do pilota

Możesz także wymienić wiersz 4, aby git push origin --tagswypchnąć wszystkie zmiany tagami z lokalnych zmian.

Na podstawie @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking, komentarze pod ich odpowiedziami i komentarze NateS pod moją odpowiedzią.

Vive
źródło
87

Usuń go za pomocą, git tag -d <tagname>a następnie utwórz ponownie przy poprawnym zatwierdzeniu.

Stuart Golodetz
źródło
3
@eedeep: Myślę, że odpowiedź Grega jest tutaj lepsza, aby była uczciwa.
Stuart Golodetz
Nie komplikuj. Usuń to, zrób to, co zrobiłeś wcześniej.
ooolala,
1
To powinna być zaakceptowana odpowiedź ze względu na jej prostotę. Nie używa też nadmiernie siły -f.
chinnychinchin
48

Staram się unikać kilku rzeczy podczas korzystania z Git.

  1. Wykorzystanie wiedzy na temat elementów wewnętrznych, np. Referencji / tagów. Staram się używać wyłącznie udokumentowanych poleceń Git i unikam używania rzeczy, które wymagają znajomości wewnętrznej zawartości katalogu .git. (To znaczy traktuję Git jako użytkownika Git, a nie programistę Git).

  2. Użycie siły, gdy nie jest wymagane.

  3. Przesadzanie. (Pchanie gałęzi i / lub wielu tagów, aby uzyskać jeden tag tam, gdzie chcę.)

Oto moje pokojowe rozwiązanie zmiany tagu, zarówno lokalnie, jak i zdalnie, bez znajomości wewnętrznych elementów Git.

Używam go, gdy poprawka oprogramowania ostatecznie ma problem i wymaga aktualizacji / ponownego wydania.

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)

githubto przykładowa nazwa zdalna, fix123to przykładowa nazwa znacznika i 790a621265przykładowe zatwierdzenie.

Ivan
źródło
26

Zostawię tutaj kolejną formę tego polecenia, która odpowiada moim potrzebom. Byłem
tag, v0.0.1.2który chciałem przenieść.

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

I wtedy:

$ git push --tags --force
Nakilon
źródło
dobrze, dziękuję, 2 proste i proste polecenia
Sérgio
10

Jeszcze jeden sposób:

Przenieś tag w zdalnym repozytorium (w razie potrzeby zastąp HEAD innym).

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

Pobierz zmiany z powrotem.

$ git fetch --tags
Алексей Югов
źródło
Jest to bardziej „transakcyjne” niż inne odpowiedzi.
Justin M. Keyes
9

Alias, aby przenieść jeden znacznik do innego zatwierdzenia.

W swojej próby, aby przenieść popełnić z e2ea1639 hash zrobić: git tagm v0.1 e2ea1639.

W przypadku tagów wypychanych użyj git tagmp v0.1 e2ea1639.

Oba aliasy przechowują oryginalną datę i wiadomość. Jeśli używasz git tag -d, utraciłeś oryginalną wiadomość.

Zapisz je w swoim .gitconfigpliku

# 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
źródło
1

Jeśli chcesz przenieść tag z adnotacjami, zmieniając tylko ukierunkowane zatwierdzenie, ale zachowując komunikat adnotacji i inne użycie metadanych:

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 {}
}

użycie: moveTag <tag-to-move> <target>

Powyższa funkcja została opracowana przez odwołanie do teerapap / git-move-annotated-tag.sh .

vossad01
źródło
1
Wydaje się, że nie jest to już potrzebne: git tag -f -a my_tagzachowuje już wiadomość z poprzedniej wiadomości (w wersji git 2.11.0).
Matthijs Kooijman,