Thẻ đã tồn tại trong lỗi "từ xa" sau khi tạo lại thẻ git


142

Tôi nhận được lỗi sau khi tôi chạy các bước dưới đây:

To git@provider.com:username/repo-name.git
 ! [rejected]        dev -> dev (already exists)
error: failed to push some refs to 'git@provider.com:username/repo-name.git'
hint: Updates were rejected because the tag already exists in the remote.
  1. Tạo kho lưu trữ
  2. Nhân bản repo trên máy cục bộ.
  3. Sửa đổi tệp README, cam kết thay đổi và đẩy cam kết.
  4. Thẻ đã tạo dev:git tag dev
  5. Thẻ đẩy: git push --tags
  6. Sửa đổi tệp README, cam kết thay đổi và đẩy cam kết.
  7. Đã xóa thẻ dev, tạo lại và đẩy thẻ:

    git tag -d dev
    git tag dev
    git push --tags
    

Tại sao chuyện này đang xảy ra?

Tôi đang trên Mac. Bạn bè của tôi sử dụng Linux (Ubuntu) không gặp phải vấn đề này. Tôi biết rằng tôi có thể sử dụng git push --tags -fđể buộc cập nhật thẻ, nhưng điều này rất nguy hiểm (ví dụ: viết lại một cam kết chỉ do nhầm lẫn trong thẻ, không phải trong chi nhánh).


1
Các cam kết không được thực hiện "trong các thẻ" hoặc "trong các nhánh" (mặc dù nó chắc chắn có cảm giác như trường hợp sau). Trong thực tế, tên thẻ và nhánh chỉ đơn giản là trỏ đến (một, một) cam kết. Xem câu trả lời dưới đây.

8
điều này làm việc cho tôi git pull --tagssau đógit push origin --tags
cưa

Câu trả lời:


175

Chỉnh sửa, ngày 24 tháng 11 năm 2016: câu trả lời này rõ ràng là phổ biến, vì vậy tôi đang thêm một ghi chú ở đây. Nếu bạn thay thế một thẻ trên một máy chủ trung tâm, bất kỳ ai có thẻ , bất kỳ bản sao nào của kho lưu trữ máy chủ trung tâm đã có thẻ đó đều có thể giữ lại thẻ cũ . Vì vậy, trong khi điều này cho bạn biết làm thế nào để làm điều đó, hãy thực sự chắc chắn rằng bạn muốn làm điều đó. Bạn sẽ cần phải nhờ tất cả những người đã có thẻ "sai" xóa "thẻ sai" của họ và thay thế bằng "thẻ đúng" mới.

Thử nghiệm trong Git 2.10 / 2.11 cho thấy giữ lại thẻ cũ là hành vi mặc định cho các máy khách đang chạy git fetchvà cập nhật là hành vi mặc định cho các máy khách đang chạy git fetch --tags.

(Câu trả lời gốc sau.)


Khi bạn yêu cầu đẩy thẻ, hãy git push --tagsgửi (cùng với mọi cam kết và các đối tượng khác cần thiết và mọi cập nhật ref khác từ cài đặt đẩy) đến từ xa một yêu cầu cập nhật của biểu mẫu . (Chà, nó gửi rất nhiều: một trong số đó cho mỗi thẻ.)new-sha1 refs/tags/name

Yêu cầu cập nhật được điều chỉnh bởi điều khiển từ xa để thêm old-sha1(hoặc một lần nữa, một cho mỗi thẻ), sau đó được gửi đến các móc nhận trước và / hoặc cập nhật (bất kỳ móc nào tồn tại trên điều khiển từ xa). Những cái móc đó có thể quyết định cho phép hoặc từ chối việc tạo / xóa / cập nhật thẻ.

Các old-sha1giá trị là hoàn toàn số không "null" SHA-1 nếu thẻ đã được tạo ra. Đây new-sha1là null SHA-1 nếu thẻ đang bị xóa. Mặt khác, cả hai giá trị SHA-1 là giá trị thực, hợp lệ.

Ngay cả khi không có móc, vẫn có một loại "móc tích hợp" cũng được chạy: điều khiển từ xa sẽ từ chối di chuyển thẻ trừ khi bạn sử dụng cờ "bắt buộc" (mặc dù "móc tích hợp" luôn ổn với cả hai "thêm" và "xóa"). Thông báo từ chối mà bạn nhìn thấy đang đến từ móc tích hợp này. (Ngẫu nhiên, cái móc tích hợp tương tự này cũng từ chối các bản cập nhật chi nhánh không được chuyển tiếp nhanh.) 1

Tuy nhiên, đây là một trong những chìa khóa để hiểu những gì đang diễn ra trên sàn git pushnhảy, không biết liệu điều khiển từ xa có thẻ đó hay không và nếu có thì giá trị SHA-1 của nó là gì. Nó chỉ nói "đây là danh sách đầy đủ các thẻ của tôi, cùng với các giá trị SHA-1 của chúng". Điều khiển từ xa so sánh các giá trị và nếu có bổ sung và / hoặc thay đổi, hãy chạy các móc trên đó. (Đối với các thẻ giống nhau, hoàn toàn không có gì. Đối với các thẻ bạn không có, chúng cũng không có gì!)

Nếu bạn xóa thẻ cục bộ, sau đó push, việc đẩy của bạn chỉ đơn giản là không chuyển thẻ. Điều khiển từ xa giả định không có thay đổi nên được thực hiện.

Nếu bạn xóa thẻ cục bộ, sau đó tạo thẻ trỏ đến một địa điểm mới, sau đó push, lần đẩy của bạn sẽ chuyển thẻ và từ xa sẽ xem đây là thay đổi thẻ và từ chối thay đổi, trừ khi đó là lực đẩy.

Vì vậy, bạn có hai lựa chọn:

  • làm một lực đẩy, hoặc
  • xóa thẻ trên điều khiển từ xa.

Loại thứ hai có thể qua git push2 mặc dù xóa thẻ trong nước và pushing không có tác dụng. Giả sử tên của điều khiển từ xa là originvà thẻ bạn muốn xóa là dev:

git push origin :refs/tags/dev

Điều này yêu cầu điều khiển từ xa để xóa thẻ. Sự hiện diện hay vắng mặt của thẻ devtrong kho lưu trữ cục bộ của bạn là không liên quan; loại này push, với tư cách là một refspec, là một cú đẩy xóa thuần túy.:remoteref

Điều khiển từ xa có thể hoặc không cho phép xóa thẻ (tùy thuộc vào bất kỳ móc thêm nào được thêm vào). Nếu nó cho phép xóa, thì thẻ sẽ biến mất và thứ hai git push --tags, khi bạn có một devthẻ cục bộ trỏ đến một số đối tượng repo thẻ cam kết hoặc chú thích, hãy gửi devthẻ mới của bạn . Trên điều khiển từ xa, devbây giờ sẽ là một thẻ mới được tạo, vì vậy điều khiển từ xa có thể sẽ cho phép đẩy (một lần nữa điều này phụ thuộc vào bất kỳ móc thêm nào được thêm vào).

Việc đẩy lực đơn giản hơn. Nếu bạn muốn chắc chắn không cập nhật bất cứ điều gì khác hơn so với thẻ, chỉ nói git pushđể đẩy duy nhất mà một refspec:

git push --force origin refs/tags/dev:refs/tags/dev

(lưu ý: bạn không cần --tagsnếu bạn rõ ràng chỉ đẩy một thẻ ref-spec).


1 Tất nhiên, lý do cho hook tích hợp này là để giúp thực thi hành vi mà những người dùng khác của cùng một repo từ xa mong đợi: rằng các nhánh không được tua lại và các thẻ không di chuyển. Nếu bạn ép buộc, bạn nên cho những người dùng khác biết bạn đang làm điều này, để họ có thể sửa lỗi cho nó. Lưu ý rằng "các thẻ không di chuyển chút nào" mới được thi hành bởi Git 1.8.2; các phiên bản trước sẽ cho phép thẻ "di chuyển về phía trước" trong biểu đồ cam kết, giống như tên chi nhánh. Xem ghi chú phát hành git 1.8.2 .

2 Thật tầm thường nếu bạn có thể đăng nhập từ xa. Chỉ cần vào kho Git ở đó và chạy git tag -d dev. Lưu ý rằng một trong hai cách mà xóa việc xóa thẻ trên điều khiển từ xa hoặc sử dụng git pushđể xóa nó, có một khoảng thời gian khi bất kỳ ai truy cập vào điều khiển từ xa sẽ thấy rằng devthẻ bị thiếu. (Họ sẽ tiếp tục có thẻ cũ của riêng họ , nếu họ đã có thẻ đó và thậm chí họ có thể đẩy thẻ cũ của họ trở lại trước khi bạn có thể đẩy thẻ mới.)


Điều này chỉ xảy ra trong các phiên bản mới của git? Tôi có 1.7.9.5và tôi không có vấn đề này ...
Ionică Bizău

2
Tôi có một bộ nhớ mơ hồ về việc git push --tagschỉ tự động thay đổi thẻ trong các phiên bản cũ hơn của git mà không có --force. Tôi đã thử nghiệm điều này dưới 1.8.4, và bạn cần --force, hoặc kỹ thuật cập nhật hai giai đoạn.

2
@ John update: cập nhật: đó là hành vi mới kể từ ngày 1.8.2, theo ghi chú phát hành . Tôi cũng sẽ chỉnh sửa nó thành chú thích 1.

Không biết làm thế nào tôi gặp phải tình huống này, nhưng điều này đã khiến một thẻ bị xóa và được tạo lại trong một trice.
RiggsFolly

4
Làm thế nào để bạn thực hiện một động tác đẩy nếu bạn không có jedi?
Fonix

54

Trong Mac SourceTree chỉ bỏ chọn hộp kiểm Đẩy tất cả các thẻ :

nhập mô tả hình ảnh ở đây


3
hahahah người đàn ông đơn giản như vậy, tôi đã đọc câu trả lời được chấp nhận và tôi nghĩ rằng tôi sẽ làm điều này lên
MegaManX

10
Đây chỉ là để khắc phục nó mà không thực sự giải quyết vấn đề. Điều này không giải quyết được tên thẻ bỏ lỡ khớp ở xa và cục bộ.
amalBit

1
làm việc cho phiên bản windows là tốt! cảm ơn vì đã cứu chúng tôi khỏi việc đọc câu trả lời được chấp nhận từ lâu mà bỏ qua những người dùng sourcetree, những người không quan tâm đến những gì đang diễn ra trong dấu nhắc lệnh :)
schlingel

19

khá đơn giản nếu bạn đang sử dụng SourceTree .

nhập mô tả hình ảnh ở đây Về cơ bản, bạn chỉ cần xóa và thêm lại thẻ xung đột:

  1. Chuyển đến tab Kho lưu trữ -> Thẻ -> Xóa thẻ
  2. Chọn tên thẻ xung đột
  3. Kiểm tra Xóa thẻ từ tất cả các điều khiển từ xa
  4. Nhấn Xóa
  5. Tạo thẻ mới có cùng tên với cam kết phù hợp
  6. Đảm bảo kiểm tra Đẩy tất cả các thẻ khi đẩy các thay đổi của bạn sang điều khiển từ xa

16

Nếu bạn muốn CẬP NHẬT một thẻ, hãy nói nó1.0.0

  1. git checkout 1.0.0
  2. thay đổi
  3. git ci -am 'modify some content'
  4. git tag -f 1.0.0
  5. xóa thẻ từ xa trên github: git push origin --delete 1.0.0
  6. git push origin 1.0.0

LÀM XONG


12

Có vẻ như tôi đã muộn về vấn đề này và / hoặc nó đã được trả lời, nhưng, điều có thể làm là: (trong trường hợp của tôi, tôi chỉ có một thẻ cục bộ nên tôi đã xóa thẻ cũ và dán lại bằng :

git tag -d v1.0
git tag -a v1.0 -m "My commit message"

Sau đó:

git push --tags -f

Điều đó sẽ cập nhật tất cả các thẻ trên điều khiển từ xa.

Có thể nguy hiểm! Sử dụng có nguy cơ riêng.


1
Điều này đã làm điều đó cho tôi! Các thẻ chỉ ở địa phương và không ở trong điều khiển từ xa :)
pgarciacamou

4

Lý do bạn bị từ chối là thẻ của bạn bị mất đồng bộ hóa với phiên bản từ xa. Đây là hành vi tương tự với các chi nhánh.

đồng bộ hóa với thẻ từ xa thông qua git pull --rebase <repo_url> +refs/tags/<TAG>và sau khi bạn đồng bộ hóa, bạn cần quản lý xung đột . Nếu bạn đã cài đặt Diftool (ví dụ: meld), hãy git mergetool meldsử dụng nó để đồng bộ hóa từ xa và giữ các thay đổi của bạn.

Lý do bạn kéo theo cờ --rebase là vì bạn muốn đặt công việc của mình lên trên điều khiển từ xa để bạn có thể tránh các xung đột khác.

Ngoài ra, điều tôi không hiểu là tại sao bạn lại xóa devthẻ và tạo lại nó ??? Thẻ được sử dụng để chỉ định phiên bản phần mềm hoặc các mốc quan trọng. Ví dụ về thẻ git v0.1dev, v0.0.1alpha, v2.3-cr(cr - ứng cử viên phát hành) và vân vân ..


Một cách khác bạn có thể giải quyết vấn đề này là vấn đề a git reflogvà đi đến thời điểm bạn đẩy devthẻ trên điều khiển từ xa. Sao chép id xác nhậngit reset --mixed <commmit_id_from_reflog>bằng cách này bạn biết thẻ của mình đã được đồng bộ hóa với điều khiển từ xa tại thời điểm bạn đẩy nó và sẽ không có xung đột nào phát sinh.


Ví dụ: nếu bạn muốn gắn thẻ một cam kết hiện đang được sản xuất. Sau đó, bạn có phải xóa thẻ sản xuất cũ khỏi một cam kết cụ thể không, đồng thời tạo và đẩy thẻ mới cho cam kết sau khi phát hành sản xuất mới.
Ville Miekk-oja

2

Trong Windows SourceTree, bỏ chọn Push all tags to remotes.

nhập mô tả hình ảnh ở đây


0

Một số câu trả lời tốt ở đây. Đặc biệt là một bởi @torek . Tôi nghĩ rằng tôi sẽ thêm công việc này với một chút giải thích cho những người vội vàng.

Tóm lại, điều xảy ra là khi bạn di chuyển một thẻ cục bộ, nó sẽ thay đổi thẻ từ một giá trị cam kết không Null thành một giá trị khác. Tuy nhiên, vì git (như một hành vi mặc định) không cho phép thay đổi các thẻ từ xa không Null, bạn không thể đẩy thay đổi.

Cách khắc phục là xóa thẻ (và đánh dấu xóa tất cả các điều khiển từ xa). Sau đó tạo cùng một thẻ và đẩy.

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.