Làm cách nào tôi có thể di chuyển thẻ trên nhánh git sang một cam kết khác?


858

Tôi đã tạo một thẻ trên nhánh chính được gọi v0.1như thế này:

git tag -a v0.1

Nhưng sau đó tôi nhận ra rằng vẫn còn một số thay đổi tôi cần để hợp nhất thành bản phát hành 0.1, vì vậy tôi đã làm điều đó. Nhưng bây giờ v0.1thẻ của tôi bị kẹt (để gọi tương tự ghi chú sau nó) cam kết sai. Tôi muốn nó bị kẹt ở lần xác nhận gần đây nhất trên master, nhưng thay vào đó, nó bị kẹt ở lần xác nhận gần đây thứ hai trên master.

Làm thế nào tôi có thể di chuyển nó đến cam kết gần đây nhất trên chủ?

Câu trả lời:


1200

Sử dụng -ftùy chọn để git tag:

-f
--force

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

Bạn có thể muốn sử dụng -fkết hợp với -ađể buộc tạo một thẻ chú thích thay vì một thẻ không chú thích.

Thí dụ

  1. Xóa thẻ trên bất kỳ điều khiển từ xa trước khi bạn đẩy

    git push origin :refs/tags/<tagname>
    
  2. Thay thế thẻ để tham chiếu các cam kết gần đây nhất

    git tag -fa <tagname>
    
  3. Đẩy thẻ vào nguồn gốc từ xa

    git push origin master --tags
    

90
Nó có thể là một ý tưởng tốt để xóa thẻ trên bất kỳ điều khiển từ xa trước khi bạn cũng đẩy, bằng cách làm điều này: git push origin :refs/tag/<tagname>và sau đó làm git tag -fa <tagname>và sau đó git push origin master --tags. Nếu không, bạn có thể kết thúc với những thứ lạ trong danh sách ref trên điều khiển từ xa với ^ và {} ký tự được thêm vào. Cảm ơn Dan tại codebasehq.com đã chỉ ra điều này.
eedeep

47
@eedeep: Sửa chữa nhỏ - thay vì :refs/tag/<tagname>nó nên được :refs/tags/<tagname>.
Ben Hocking

8
Điều này chỉ hoạt động nếu bạn không đẩy mã ra khỏi máy. Nếu bạn có, câu trả lời tốt nhất là "có rất nhiều con số trên thế giới" vì có lẽ nó không đáng để bận tâm.
Chris Huang-Leaver

33
Nếu bạn đã đẩy thẻ của mình, bạn vẫn có thể cập nhật thẻ từ xa bằng một lần đẩy bắt buộcgit push -f origin <tagname>
rc_luke

11
Điều không được đề cập ở đây và trong các tài liệu là, điều này thực sự sẽ di chuyển thông điệp thẻ, nếu không có thông báo mới nào được đưa ra.
Twonky

259

Chính xác hơn, bạn phải buộc thêm thẻ, sau đó đẩy với tùy chọn --tags và -f:

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

171

Để tổng hợp nếu điều khiển từ xa của bạn được gọi originvà bạn đang làm việc trên masterchi nhánh:

git tag -d <tagname>
git push origin :refs/tags/<tagname>
git tag <tagname> <commitId>
git push origin <tagname>
  • Dòng 1 xóa thẻ trong env cục bộ.
  • Dòng 2 xóa thẻ trong env từ xa.
  • Dòng 3 thêm thẻ vào các cam kết khác nhau
  • Dòng 4 đẩy sự thay đổi đến điều khiển từ xa

Bạn cũng có thể trao đổi dòng 4 để git push origin --tagsđẩy tất cả các thay đổi bằng các thẻ từ các thay đổi cục bộ của bạn.

Dựa trên @ stuart-golodetz, @ greg-hewgill, @eedeep, @ ben-hocking câu trả lời, nhận xét bên dưới câu trả lời của họ và nhận xét của NateS bên dưới câu trả lời của tôi.


87

Xóa nó với git tag -d <tagname>và sau đó tạo lại nó trên cam kết chính xác.


3
@eedeep: Tôi nghĩ rằng phản ứng của Greg thực sự tốt hơn ở đây để công bằng.
Stuart Golodetz

Giữ cho nó đơn giản. Xóa nó, làm những gì bạn đã làm trước đó một lần nữa.
ooolala

1
Đây phải là câu trả lời được chấp nhận, vì sự đơn giản của nó. Cũng không sử dụng lực -f quá mức.
chinnychinchin

48

Tôi cố gắng tránh một vài điều khi sử dụng Git.

  1. Sử dụng kiến ​​thức của các bên trong, ví dụ refs / tags. Tôi cố gắng chỉ sử dụng các lệnh Git được ghi lại và tránh sử dụng những thứ đòi hỏi kiến ​​thức về nội dung bên trong của thư mục .git. (Nghĩa là, tôi coi Git là người dùng Git chứ không phải nhà phát triển Git.)

  2. Việc sử dụng vũ lực khi không bắt buộc.

  3. Làm quá nhiều việc. (Đẩy một nhánh và / hoặc nhiều thẻ, để có một thẻ ở nơi tôi muốn.)

Vì vậy, đây là giải pháp phi bạo lực của tôi để thay đổi thẻ, cả cục bộ và từ xa, mà không có kiến ​​thức về nội bộ Git.

Tôi sử dụng nó khi sửa lỗi phần mềm cuối cùng có vấn đề và cần được cập nhật / phát hành lại.

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)

githublà một tên từ xa mẫu, fix123là một tên thẻ mẫu và 790a621265một cam kết mẫu.


26

Tôi sẽ rời khỏi đây chỉ là một hình thức khác của lệnh này phù hợp với nhu cầu của tôi.
Có một thẻ v0.0.1.2mà tôi muốn di chuyển.

$ git tag -f v0.0.1.2 63eff6a

Updated tag 'v0.0.1.2' (was 8078562)

Và sau đó:

$ git push --tags --force

tốt, cảm ơn bạn, 2 lệnh đơn giản và đơn giản
Sérgio

10

Một cách khác:

Di chuyển thẻ trong repo từ xa. (Thay thế Head bằng bất kỳ cái nào khác nếu cần.)

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

Lấy các thay đổi trở lại.

$ git fetch --tags

Đây là "giao dịch" nhiều hơn các câu trả lời khác.
Justin M. Keyes

9

Bí danh để di chuyển một thẻ đến một cam kết khác.

Trong mẫu của bạn, để di chuyển cam kết với hàm băm e2ea1639 làm : git tagm v0.1 e2ea1639.

Đối với các thẻ đẩy, sử dụng git tagmp v0.1 e2ea1639.

Cả hai bí danh giữ cho bạn ngày ban đầu và tin nhắn. Nếu bạn sử dụng, git tag -dbạn bị mất tin nhắn ban đầu của bạn.

Lưu chúng vào .gitconfigtập tin của bạn

# 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

Nếu bạn muốn di chuyển thẻ chú thích, chỉ thay đổi cam kết được nhắm mục tiêu nhưng duy trì thông báo chú thích và sử dụng siêu dữ liệu khác:

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

cách sử dụng: moveTag <tag-to-move> <target>

Hàm trên được phát triển bằng cách tham chiếu teerapap / git-move-annotated-tag.sh .


1
Có vẻ như điều này không còn cần thiết nữa: git tag -f -a my_tagđã lưu giữ thông điệp của tin nhắn trước đó (với phiên bản git 2.11.0).
Matthijs Kooijman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.