Bagaimana saya bisa memindahkan tag pada cabang git ke komit yang berbeda?

858

Saya membuat tag pada cabang master yang disebut v0.1seperti ini:

git tag -a v0.1

Tapi kemudian saya menyadari masih ada beberapa perubahan yang saya butuhkan untuk bergabung menjadi master untuk rilis 0.1, jadi saya melakukan itu. Tapi sekarang v0.1tag saya macet (untuk memohon analogi post-it note) komit yang salah. Saya ingin itu terjebak pada komit terbaru pada master, tetapi sebaliknya terjebak pada komit terbaru kedua pada master.

Bagaimana saya bisa memindahkannya ke komit terbaru pada master?

Eedeep
sumber

Jawaban:

1200

Gunakan -fopsi untuk git tag:

-f
--force

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

Anda mungkin ingin menggunakannya -fbersamaan dengan -amemaksa-membuat tag beranotasi alih-alih yang tidak beranotasi.

Contoh

  1. Hapus tag pada remote mana saja sebelum Anda mendorong

    git push origin :refs/tags/<tagname>
    
  2. Ganti tag untuk referensi komit terbaru

    git tag -fa <tagname>
    
  3. Dorong tag ke asal yang jauh

    git push origin master --tags
    
Greg Hewgill
sumber
90
Mungkin merupakan ide yang baik untuk menghapus tag pada remote mana pun sebelum Anda mendorongnya juga, dengan melakukan ini: git push origin :refs/tag/<tagname>lalu lakukan git tag -fa <tagname>kemudian git push origin master --tags. Kalau tidak, Anda mungkin berakhir dengan hal-hal aneh dalam daftar referensi pada remote dengan karakter ^ dan {} ditambahkan. Terima kasih kepada Dan di codebasehq.com untuk menunjukkan ini.
eedeep
47
@eedeep: Koreksi kecil - bukannya :refs/tag/<tagname>seharusnya :refs/tags/<tagname>.
Ben Hocking
8
Ini hanya berfungsi jika Anda belum mendorong kode dari mesin Anda. Jika sudah, jawaban terbaik adalah 'ada banyak angka di dunia' karena mungkin tidak sepadan dengan kerumitannya.
Chris Huang-Leaver
33
Jika Anda telah mendorong tag Anda, Anda masih dapat memperbarui tag jarak jauh dengan dorongan paksagit push -f origin <tagname>
rc_luke
11
Apa yang tidak disebutkan di sini dan di dalam dokumen adalah, bahwa ini memang memindahkan pesan tag, jika tidak ada pesan baru yang diberikan.
Twonky
259

Lebih tepatnya, Anda harus memaksa penambahan tag, lalu dorong dengan opsi --tags dan -f:

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

Untuk meringkas jika remote Anda dipanggil origindan Anda bekerja di mastercabang:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • Baris 1 menghapus tag di id lokal.
  • Baris 2 menghapus tag di remote env.
  • Baris 3 menambahkan tag ke komit yang berbeda
  • Jalur 4 mendorong perubahan ke remote

Anda juga dapat bertukar baris 4 git push origin --tagsuntuk mendorong semua perubahan dengan tag dari perubahan lokal Anda.

Mendasarkan pada @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking jawaban, komentar di bawah jawaban mereka dan komentar NateS di bawah jawaban saya.

Vive
sumber
87

Hapus dengan git tag -d <tagname>dan kemudian buat kembali di komit yang benar.

Stuart Golodetz
sumber
3
@eedeep: Saya pikir respons Greg sebenarnya lebih baik di sini agar adil.
Stuart Golodetz
Tetap sederhana. Hapus itu, lakukan apa yang kamu lakukan sebelumnya.
ooolala
1
Ini harus menjadi jawaban yang diterima, karena kesederhanaannya. Juga tidak menggunakan kekuatan -f secara berlebihan.
chinnychinchin
48

Saya mencoba menghindari beberapa hal ketika menggunakan Git.

  1. Menggunakan pengetahuan internal, misalnya ref / tag. Saya mencoba hanya menggunakan perintah Git yang didokumentasikan dan menghindari menggunakan hal-hal yang membutuhkan pengetahuan tentang isi internal direktori .git. (Artinya, saya memperlakukan Git sebagai pengguna Git dan bukan pengembang Git.)

  2. Penggunaan kekuatan saat tidak diperlukan.

  3. Hal-hal berlebihan. (Mendorong cabang dan / atau banyak tag, untuk mendapatkan satu tag di tempat yang saya inginkan.)

Jadi di sini adalah solusi non-kekerasan saya untuk mengubah tag, baik secara lokal maupun jarak jauh, tanpa sepengetahuan internal Git.

Saya menggunakannya ketika perbaikan perangkat lunak pada akhirnya memiliki masalah dan perlu diperbarui / dirilis ulang.

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)

githubadalah nama sampel jarak jauh, fix123adalah nama tag sampel, dan 790a621265sampel komit.

Ivan
sumber
26

Saya akan meninggalkan di sini hanya bentuk lain dari perintah ini yang sesuai dengan kebutuhan saya.
Ada tag v0.0.1.2yang ingin saya pindahkan.

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

Lalu:

$ git push --tags --force
Nakilon
sumber
bagus, terima kasih, 2 perintah sederhana dan sederhana
Sérgio
10

Satu cara lain:

Pindahkan tag dalam repo jarak jauh. (Ganti HEAD dengan yang lain jika perlu.)

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

Ambil perubahan kembali.

$ git fetch --tags
Алексей Югов
sumber
Ini lebih "transaksional" daripada jawaban lainnya.
Justin M. Keyes
9

Alias ​​untuk memindahkan satu tag ke komit yang berbeda.

Dalam sampel Anda, untuk bergerak melakukan dengan e2ea1639 hash lakukan: git tagm v0.1 e2ea1639.

Untuk tag yang didorong, gunakan git tagmp v0.1 e2ea1639.

Kedua alias membuat Anda mendapatkan tanggal dan pesan asli. Jika Anda menggunakan git tag -dAnda kehilangan pesan asli Anda.

Simpan di .gitconfigfile Anda

# 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
sumber
1

Jika Anda ingin memindahkan tag beranotasi, mengubah hanya komit yang ditargetkan tetapi mempertahankan pesan anotasi dan penggunaan metadata lainnya:

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

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

Fungsi di atas dikembangkan dengan merujuk teerapap / git-move-annotated-tag.sh .

vossad01
sumber
1
Tampaknya ini tidak lagi diperlukan: git tag -f -a my_tagsudah mempertahankan pesan dari pesan sebelumnya (dengan git versi 2.11.0).
Matthijs Kooijman