ฉันจะย้ายแท็กบนสาขา git ไปยังการคอมมิทที่ต่างกันได้อย่างไร


858

ฉันสร้างแท็กในสาขาหลักที่เรียกว่าv0.1:

git tag -a v0.1

แต่จากนั้นฉันก็รู้ว่ายังมีการเปลี่ยนแปลงบางอย่างที่ฉันต้องรวมเข้ากับต้นแบบเพื่อการเปิดตัว 0.1 ดังนั้นฉันจึงทำเช่นนั้น แต่ตอนนี้v0.1แท็กของฉันติดอยู่ (เพื่อเรียกการเปรียบเทียบโพสต์ - อิท) การกระทำผิด ฉันต้องการให้มันติดอยู่กับการคอมมิทล่าสุดของมาสเตอร์ แต่มันจะติดอยู่กับคอมมิทล่าสุดที่สอง

ฉันจะย้ายไปยังการมอบหมายล่าสุดได้อย่างไร?

คำตอบ:


1199

ใช้-fตัวเลือกเพื่อgit tag:

-f
--force

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

คุณอาจต้องการใช้-fร่วมกับ-aเพื่อบังคับให้สร้างแท็กที่มีคำอธิบายประกอบแทนที่จะเป็นแท็กที่ไม่มีคำอธิบายประกอบ

ตัวอย่าง

  1. ลบแท็กบนรีโมตก่อนที่คุณจะกด

    git push origin :refs/tags/<tagname>
    
  2. แทนที่แท็กเพื่ออ้างอิงการกระทำล่าสุด

    git tag -fa <tagname>
    
  3. ผลักแท็กไปยังแหล่งกำเนิดระยะไกล

    git push origin master --tags
    

90
มันอาจจะเป็นความคิดที่ดีที่จะลบแท็กในระยะไกล ๆ ก่อนที่คุณจะผลักดันมากเกินไปโดยการทำเช่นนี้git push origin :refs/tag/<tagname>แล้วทำแล้วgit tag -fa <tagname> git push origin master --tagsมิฉะนั้นคุณอาจท้ายเรื่องแปลก ๆ ในรายการ refs บนรีโมทด้วยอักขระ ^ และ {} ที่ต่อท้าย ขอบคุณ Dan ที่ codebasehq.com ที่ชี้เรื่องนี้
eedeep

47
@eedeep: ไมเนอร์แก้ไข - แทนมันควรจะเป็น:refs/tag/<tagname> :refs/tags/<tagname>
Ben Hocking

8
ใช้งานได้เฉพาะในกรณีที่คุณไม่ได้ผลักรหัสออกจากเครื่อง หากคุณมีคำตอบที่ดีที่สุดคือ 'มีตัวเลขมากมายในโลก' เนื่องจากอาจไม่คุ้มกับความยุ่งยาก
Chris Huang-Leaver

33
หากคุณผลักแท็กไปแล้วคุณยังคงสามารถอัปเดตแท็กระยะไกลได้ด้วยการบังคับให้กดgit push -f origin <tagname>
rc_luke

11
สิ่งที่ไม่ได้กล่าวถึงที่นี่และในเอกสารคือว่านี่เป็นการย้ายข้อความแท็กหากไม่มีข้อความใหม่ให้
Twonky

259

แม่นยำยิ่งขึ้นคุณต้องบังคับให้เพิ่มแท็กจากนั้นกดด้วยตัวเลือก - แท็กและ -f:

git tag -f -a <tagname>
git push -f --tags

171

เพื่อสรุปว่ารีโมทของคุณถูกเรียกใช้originและคุณทำงานอยู่ในmasterสาขา:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • บรรทัดที่ 1 ลบแท็กใน local env
  • บรรทัด 2 ลบแท็กใน remote env
  • บรรทัดที่ 3 เพิ่มแท็กให้กับการคอมมิทที่ต่างกัน
  • บรรทัดที่ 4 ผลักการเปลี่ยนแปลงไปยังรีโมต

คุณสามารถแลกเปลี่ยนบรรทัดที่ 4 เพื่อgit push origin --tagsผลักดันการเปลี่ยนแปลงทั้งหมดด้วยแท็กจากการเปลี่ยนแปลงในเครื่องของคุณ

การอ้างอิงบน @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking คำตอบความคิดเห็นด้านล่างคำตอบและความคิดเห็นของ NateS ด้านล่างคำตอบของฉัน


87

ลบด้วยgit tag -d <tagname>แล้วสร้างมันใหม่ในการกระทำที่ถูกต้อง


3
@eedeep: ฉันคิดว่าคำตอบของ Greg นั้นดีกว่าจริง ๆ
Stuart Golodetz

ง่าย ๆ เข้าไว้. ลบออกทำสิ่งที่คุณเคยทำอีกครั้ง
ooolala

1
นี่ควรเป็นคำตอบที่ยอมรับได้สำหรับความเรียบง่ายของมัน ยังไม่ได้ใช้แรง f- มากเกินไป
chinnychinchin

48

ฉันพยายามหลีกเลี่ยงบางสิ่งเมื่อใช้ Git

  1. การใช้ความรู้เกี่ยวกับ internals เช่น refs / tags ฉันพยายามใช้คำสั่ง Git ที่ทำเป็นเอกสารเท่านั้นและหลีกเลี่ยงการใช้สิ่งที่ต้องการความรู้เกี่ยวกับเนื้อหาภายในของไดเรกทอรี. git (กล่าวคือฉันปฏิบัติต่อ Git ในฐานะผู้ใช้ Git ไม่ใช่ผู้พัฒนา Git)

  2. การใช้กำลังเมื่อไม่จำเป็น

  3. ทำมากเกินไป (ผลักสาขาและ / หรือแท็กจำนวนมากเพื่อรับแท็กหนึ่งตำแหน่งที่ฉันต้องการ)

ดังนั้นนี่คือโซลูชันที่ไม่ใช้ความรุนแรงสำหรับการเปลี่ยนแท็กทั้งในและนอกสถานที่โดยไม่มีความรู้เกี่ยวกับ Git internals

ฉันใช้เมื่อการแก้ไขซอฟต์แวร์ในที่สุดมีปัญหาและจำเป็นต้องได้รับการอัปเดต / รีลีสใหม่

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เป็นชื่อรีโมตตัวอย่างfix123เป็นชื่อแท็กตัวอย่างและ790a621265ตัวอย่างการส่งมอบ


26

ฉันจะออกจากที่นี่เป็นอีกรูปแบบหนึ่งของคำสั่งนี้
มีแท็กv0.0.1.2ที่ฉันต้องการย้าย

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

แล้ว:

$ git push --tags --force

ดีขอบคุณ 2 คำสั่งธรรมดาและเรียบง่าย
Sérgio

10

อีกทางหนึ่ง:

ย้ายแท็กใน repo ระยะไกล (แทนที่ HEAD ด้วยอันอื่นหากจำเป็น)

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

ดึงการเปลี่ยนแปลงกลับมา

$ git fetch --tags

นี่คือ "ธุรกรรม" มากกว่าคำตอบอื่น ๆ
Justin M. Keyes

9

นามแฝงที่จะย้ายหนึ่งแท็กไปยังการส่งที่แตกต่างกัน

ในตัวอย่างของคุณที่จะย้ายกระทำกับ e2ea1639 git tagm v0.1 e2ea1639กัญชาทำ:

git tagmp v0.1 e2ea1639สำหรับแท็กผลักดันการใช้งาน

ชื่อแทนทั้งสองช่วยให้คุณวันที่และข้อความต้นฉบับ ถ้าคุณใช้git tag -dคุณทำข้อความต้นฉบับหาย

บันทึกไว้ใน.gitconfigไฟล์ของคุณ

# 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 #"

1

หากคุณต้องการย้ายแท็กที่มีคำอธิบายประกอบให้เปลี่ยนเฉพาะการคอมมิทเป้าหมาย แต่การรักษาข้อความคำอธิบายประกอบและการใช้เมตาดาต้าอื่น ๆ :

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

การใช้งาน: moveTag <tag-to-move> <target>

ฟังก์ชั่นดังกล่าวข้างต้นได้รับการพัฒนาโดยการอ้างอิงธีร / git-move-annotated-tag.sh


1
ดูเหมือนว่ามันไม่จำเป็นอีกต่อไปgit tag -f -a my_tagแล้ว: รักษาข้อความของข้อความก่อนหน้า (พร้อมด้วย git เวอร์ชัน 2.11.0)
Matthijs Kooijman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.