Có phải git fetch fetch --tags Có bao gồm cả git fetch không?


270

Một câu hỏi hay và đơn giản - chức năng của "git fetch" có phải là một tập hợp con nghiêm ngặt git fetch --tagskhông?

Tức là nếu tôi chạy git fetch --tags, có bao giờ có lý do để ngay lập tức chạy git fetchthẳng sau đó không?

Còn về git pullgit pull --tags? Cùng hoàn cảnh?


11
Bắt đầu từ Git 1..9 / 2.0 (Q1 2014), câu trả lời sẽ là . Xem câu trả lời của tôi dưới đây
VonC

3
Đối với biên tập viên đã "sửa văn bản của tôi" bằng một chỉnh sửa - người ta không nhất thiết phải viết hoa sau một dấu gạch nối hoặc từ viết tắt, vì vậy chỉnh sửa của bạn không đúng về mặt ngữ pháp, đó là lý do tại sao tôi từ chối nó.
davidA

Câu trả lời:


176

Lưu ý: bắt đầu với git 1.9 / 2.0 (Q1 2014) , git fetch --tagstìm nạp các thẻ ngoài những gì được tìm nạp bởi cùng một dòng lệnh mà không có tùy chọn.

Xem cam kết c5a84e9 của Michael Haggerty (mhagger) :

Trước đây, --tagstùy chọn " " của fetch được coi là tương đương với việc chỉ định refspec

refs/tags/*:refs/tags/*

trên dòng lệnh; đặc biệt, nó làm cho remote.<name>.refspeccấu hình bị bỏ qua.

Nhưng nó không phải là rất hữu ích để lấy thẻ mà không có cũng lấy tài liệu tham khảo khác, trong khi nó khá hữu ích để có thể lấy thẻ , thêm vào tài liệu tham khảo khác.
Vì vậy, thay đổi ngữ nghĩa của tùy chọn này để làm sau.

Nếu người dùng muốn lấy chỉ thẻ, sau đó nó vẫn còn có thể chỉ định một refspec rõ ràng:

git fetch <remote> 'refs/tags/*:refs/tags/*'

Xin lưu ý rằng tài liệu trước 1.8.0.3 không rõ ràng về khía cạnh fetch --tagshành vi "" này.
Cam kết f0cb2f1 (2012-12-14) fetch --tagslàm cho tài liệu phù hợp với hành vi cũ.
Cam kết này thay đổi tài liệu để phù hợp với hành vi mới (xem Documentation/fetch-options.txt).

Yêu cầu tất cả các thẻ được tìm nạp từ xa ngoài bất kỳ thứ gì khác đang được tìm nạp .


Vì Git 2.5 (quý 2 năm 2015) git pull --tagsmạnh mẽ hơn:

Xem cam kết 19d122b của Paul Tan ( pyokagan) , ngày 13 tháng 5 năm 2015.
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết cc77b99 , ngày 22 tháng 5 năm 2015)

pull: xóa --tagslỗi trong trường hợp ứng viên không hợp nhất

441ed41 (" git pull --tags": lỗi với thông báo tốt hơn., 2007-12-28, Git 1.5.4+), git pull --tagssẽ in một thông báo lỗi khác nếu git-fetchkhông trả về bất kỳ ứng cử viên hợp nhất nào:

It doesn't make sense to pull all tags; you probably meant:
       git fetch --tags

Điều này là do tại thời điểm đó, git-fetch --tagssẽ ghi đè bất kỳ refspecs được cấu hình nào và do đó sẽ không có ứng cử viên hợp nhất. Do đó, thông báo lỗi đã được giới thiệu để tránh nhầm lẫn.

Tuy nhiên, vì c5a84e9 ( fetch --tags: tìm nạp các thẻ ngoài các nội dung khác, 2013-10-30, Git 1.9.0+), git fetch --tagssẽ tìm nạp các thẻ ngoài bất kỳ refspec nào được định cấu hình.
Do đó, nếu không có tình huống ứng cử viên hợp nhất xảy ra, đó không phải là vì --tagsđã được đặt. Như vậy, thông báo lỗi đặc biệt này hiện không liên quan.

Để tránh nhầm lẫn, loại bỏ thông báo lỗi này.


Với Git 2.11+ (Q4 2016) git fetchthì nhanh hơn.

Xem cam kết 5827a03 (ngày 13 tháng 10 năm 2016) của Jeff King ( peff) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 9fcd144 , ngày 26 tháng 10 năm 2016)

fetch: sử dụng "quick" has_sha1_fileđể theo dõi thẻ

Khi tìm nạp từ xa có nhiều thẻ không liên quan đến các nhánh mà chúng tôi đang theo dõi, chúng tôi thường lãng phí quá nhiều chu kỳ khi kiểm tra xem đối tượng được trỏ bởi thẻ (mà chúng tôi sẽ không tìm nạp!) quá cẩn thận

Bản vá này dạy tìm nạp để sử dụng HAS_SHA1_QUICK để hy sinh độ chính xác cho tốc độ, trong trường hợp chúng ta có thể không thích hợp với việc đóng gói lại đồng thời.

Dưới đây là kết quả từ tập lệnh perf bao gồm, thiết lập một tình huống tương tự như tình huống được mô tả ở trên:

Test            HEAD^               HEAD
----------------------------------------------------------
5550.4: fetch   11.21(10.42+0.78)   0.08(0.04+0.02) -99.3%

Điều đó chỉ áp dụng cho một tình huống:

  1. Bạn có rất nhiều gói ở phía khách hàng để làm cho reprepare_packed_git()đắt tiền (phần đắt nhất là tìm các bản sao trong danh sách chưa được sắp xếp, hiện đang là bậc hai).
  2. Bạn cần một số lượng lớn các thẻ giới thiệu ở phía máy chủ là ứng cử viên để tự động theo dõi (nghĩa là khách hàng không có). Mỗi cái kích hoạt đọc lại thư mục pack.
  3. Trong các trường hợp thông thường, khách hàng sẽ tự động theo dõi các thẻ đó và sau một lần tìm nạp lớn, (2) sẽ không còn đúng nữa.
    Nhưng nếu các thẻ đó trỏ đến lịch sử bị ngắt kết nối với những gì khách hàng tìm nạp, thì nó sẽ không bao giờ tự động theo dõi và những ứng cử viên đó sẽ tác động đến nó trên mỗi lần tìm nạp.

Git 2.21 (tháng 2 năm 2019) dường như đã giới thiệu một hồi quy khi cấu hình remote.origin.fetchkhông một mặc định ( '+refs/heads/*:refs/remotes/origin/*')

fatal: multiple updates for ref 'refs/tags/v1.0.0' not allowed

Git 2.24 (Q4 2019) thêm một tối ưu hóa khác.

Xem cam kết b7e2d8b (15 tháng 9 năm 2019) của Masaya Suzuki ( draftcode) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 1d8b0df , ngày 07 tháng 10 năm 2019)

fetch: sử dụng oidsetđể giữ OID muốn tìm kiếm nhanh hơn

Trong khi git fetch, khách hàng kiểm tra xem các OID của thẻ được quảng cáo đã có trong bộ OID của yêu cầu tìm nạp chưa.
Kiểm tra này được thực hiện trong một quét tuyến tính.
Đối với một kho lưu trữ có nhiều ref, việc lặp lại quá trình quét này mất hơn 15 phút.

Để tăng tốc độ này, hãy tạo một oid_setOID cho các ref khác.


Chủ đề này trong danh sách git thảo luận về khả năng sửa đổi hành vi của git fetch <remote> <branch>các thẻ tự động theo dõi (vì nó đã cập nhật các mục đích theo dõi từ xa AGAINST ý định ban đầu): public-inbox.org/git/ trộm
ankostis

@ankostis Thú vị: như Junio ​​đề cập trong public-inbox.org/git/ , "quay lại hành vi cũ có thể là một lựa chọn để giải quyết vấn đề đang được thảo luận trong chủ đề này." (nhưng họ sẽ không: public-inbox.org/git/ Lần )
VonC

Liệu Git có thể phơi bày sự phức tạp không cần thiết hơn cho người dùng cuối, yêu cầu các lệnh nặng cú pháp đến điểm giống như các bản hack để thực hiện các hoạt động chung? Tôi không nghĩ rằng đủ nội bộ là kiến ​​thức cần thiết.
John Fantastico

1
@JohnFantastico Tôi có thể hiểu quan điểm đó. Tôi đã thấy điều đó trước đây: news.ycombinator.com/item?id=16587496 . Hoặc hackernoon.com/ bào ("Các lệnh Git chỉ là một sự trừu tượng hóa rò rỉ trên bộ lưu trữ dữ liệu.")
VonC

1
@Vadorequest Cảm ơn bạn. Tôi đã cập nhật câu trả lời và sẽ theo dõi danh sách gửi thư: public-inbox.org/git/?q=fetch
VonC

131

Lưu ý: câu trả lời này chỉ hợp lệ cho git v1.8 trở lên.

Hầu hết những điều này đã được nói trong các câu trả lời và nhận xét khác, nhưng đây là một lời giải thích ngắn gọn:

  • git fetchtìm nạp tất cả các đầu chi nhánh (hoặc tất cả được chỉ định bởi tùy chọn cấu hình remote.fetch), tất cả các cam kết cần thiết cho chúng và tất cả các thẻ có thể truy cập từ các nhánh này. Trong hầu hết các trường hợp, tất cả các thẻ đều có thể truy cập theo cách này.
  • git fetch --tagstìm nạp tất cả các thẻ, tất cả các cam kết cần thiết cho chúng. Nó sẽ không cập nhật các đầu chi nhánh, ngay cả khi chúng có thể truy cập được từ các thẻ được tìm nạp.

Tóm tắt: Nếu bạn thực sự muốn hoàn toàn cập nhật, chỉ sử dụng tìm nạp, bạn phải làm cả hai.

Nó cũng không "chậm gấp đôi" trừ khi bạn có nghĩa là về cách gõ trên dòng lệnh, trong trường hợp đó, bí danh giải quyết vấn đề của bạn. Về cơ bản không có chi phí nào trong việc đưa ra hai yêu cầu, vì họ đang yêu cầu thông tin khác nhau.


2
Cám ơn bạn đã góp ý. Tôi đang chạy git trong Cygwin qua mạng có độ trễ cao - nó chậm gấp đôi khi không có gì để tìm nạp (khoảng 5 giây).
davidA

Tuyệt vời. Liệu git-remote có hoạt động tốt hơn không? Nhìn vào nguồn một cách ngắn gọn tôi nghĩ rằng nó có thể chỉ thực hiện một cuộc gọi duy nhất - nhưng tôi không hoàn toàn chắc chắn liệu nó có lấy các thẻ không liên kết hay không. Thành thật tôi không biết nếu tôi từng thấy bất kỳ thẻ nào không nằm trên một nhánh. Với những điều tôi rút ra, cách duy nhất sẽ xảy ra nếu tôi chờ đợi quá lâu đến nỗi tôi bỏ lỡ một bản phát hành bảo trì, một bản phát hành tính năng và ngừng bảo trì bản phát hành cũ.
Cascabel

Tôi nghĩ vấn đề là 'git fetch' chỉ tìm nạp các thẻ trên các nhánh được theo dõi . Chúng tôi có một tập lệnh cho phép người dùng chọn một nhánh làm việc, vì vậy theo mặc định, có nhiều nhánh hiện không được theo dõi bởi một cá nhân.
davidA

Tôi chưa thử git-remote, nhưng nó nằm trong danh sách việc cần làm ngày càng tăng của tôi :)
davidA

7
Lưu ý rằng đó git remote updatekhông thực sự là một thay thế cho git fetchgit fetch --tags. git remote updatesẽ không cập nhật các thẻ hiện có đã thay đổi, mặc dù nó sẽ mang lại các thẻ mới. Chỉ git fetch --tagssẽ cập nhật các thẻ đã tồn tại.
larsks

48

Tôi sẽ tự trả lời điều này.

Tôi đã xác định rằng có một sự khác biệt. "git fetch --tags" có thể mang lại tất cả các thẻ, nhưng nó không mang lại bất kỳ cam kết mới nào!

Hóa ra người ta phải làm điều này để hoàn toàn "cập nhật", tức là sao chép một "git pull" mà không cần hợp nhất:

$ git fetch --tags
$ git fetch

Đây là một sự xấu hổ, vì nó chậm gấp đôi. Nếu chỉ "git fetch" có một tùy chọn để làm những gì nó thường làm mang lại tất cả các thẻ.


Thật thú vị, tôi đã không trải nghiệm điều đó (có lẽ vì repo của tôi đã được cập nhật tại thời điểm thử nghiệm.) +1
VonC

1
Làm thế nào về một ' git remote update myRemoteRepo': sẽ lấy nội dung thẻ từ xa ?
VonC

1
Tôi làm git fetchtất cả thời gian và nó liên tục kéo xuống bất kỳ cam kết mới bất kỳ thẻ mới nào. Phiên bản Git nào bạn đang chạy?
Tim Visher

4
FTR, 'git cập nhật từ xa myRemoteRepo' không hoạt động tốt - dường như không làm được những gì 'git fetch && git fetch --tags', đặc biệt là việc hợp nhất tiếp theo không có hiệu lực.
davidA

1
@TimVisher git fetchsẽ không lấy các thẻ không có trong nhật ký cam kết của chi nhánh. Giao diện người dùng jQuery thực hiện điều này chẳng hạn trên thẻ phát hành. Chúng tôi thực hiện git checkout -b temp-branch, phát hành, thêm các tệp cần thiết cho bản phát hành, phiên bản cập nhật, v.v., sau git commit -m "1.10.x" ; git tag 1.10.x; git push --tagsđó chúng tôi xóa chi nhánh tạm thời cục bộ của mình. Không có chi nhánh từ xa nào đạt được thẻ đó và git fetchsẽ không bao giờ tải xuống.
gnarf

31

Vấn đề chung ở đây là git fetchsẽ lấy +refs/heads/*:refs/remotes/$remote/*. Nếu bất kỳ cam kết nào có thẻ, những thẻ đó cũng sẽ được tìm nạp. Tuy nhiên, nếu có bất kỳ thẻ nào có thể truy cập được bởi bất kỳ chi nhánh nào trên điều khiển từ xa, chúng sẽ không được tìm nạp.

Các --tagstùy chọn chuyển mạch refspec tới +refs/tags/*:refs/tags/*. Bạn có thể yêu cầu git fetchlấy cả hai. Tôi khá chắc chắn rằng bạn chỉ cần git fetch && git fetch -tsử dụng lệnh sau:

git fetch origin "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"

Và nếu bạn muốn đặt nó làm mặc định cho repo này, bạn có thể thêm một refspec thứ hai vào tìm nạp mặc định:

git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"

Điều này sẽ thêm một fetch =dòng thứ hai trong .git/configđiều khiển từ xa này.


Tôi đã dành một thời gian để tìm cách xử lý việc này cho một dự án. Đây là những gì tôi đã đưa ra.

git fetch -fup origin "+refs/*:refs/*"

Trong trường hợp của tôi, tôi muốn các tính năng này

  • Lấy tất cả các đầu và thẻ từ xa để sử dụng refspec refs/*:refs/*
  • Ghi đè các nhánh và thẻ cục bộ bằng cách không chuyển tiếp nhanh +trước refspec
  • Ghi đè lên chi nhánh hiện đang kiểm tra nếu cần -u
  • Xóa các nhánh và thẻ không có trong điều khiển từ xa -p
  • Và buộc phải chắc chắn -f

Đây nên là câu trả lời.
hương thơm

+1 cho " --tagsTùy chọn chuyển refspec thành +refs/tags/*:refs/tags/*". Mặc dù, man git-fetchdường như chỉ định refspec mà không có hàng đầu +( refs/tags/*:refs/tags/*).
Dmitry Minkovsky

remote.origin.fetch mặc định +refs/heads/*:refs/remotes/origin/* , tức là +phiên bản, phải không? (Điều đó có nghĩa là, nguồn gốc / chi nhánh sẽ được ghi đè, bất kể nguồn gốc / chi nhánh hiện đang ở đâu tại địa phương.)
Robert Siemer

... và tại thời điểm viết, gần đây git --tags đã tìm nạp các thẻ cùng với mọi thứ khác. Xem câu trả lời của @VonC.
Robert Siemer

10

Trong hầu hết các tình huống, git fetchnên làm những gì bạn muốn, đó là 'lấy bất cứ thứ gì mới từ kho lưu trữ từ xa và đặt nó vào bản sao cục bộ của bạn mà không hợp nhất với các chi nhánh địa phương của bạn'. git fetch --tagsthực hiện chính xác điều đó, ngoại trừ việc nó không nhận được gì ngoại trừ các thẻ mới.

Theo nghĩa đó, git fetch --tagskhông có cách nào là một superset của git fetch. Thực tế nó hoàn toàn ngược lại.

git pull, tất nhiên, không có gì ngoài một trình bao bọc cho a git fetch <thisrefspec>; git merge. Đó là khuyến cáo rằng bạn đã quen với làm thủ công git fetching và git mergeing trước khi bạn thực hiện chuyển sang git pullđơn giản chỉ vì nó giúp bạn hiểu những gì git pullđang làm ở nơi đầu tiên.

Điều đó đang được nói, mối quan hệ là chính xác như với git fetch. git pulllà siêu âm của git pull --tags.


1
"Git pull là superset của git pull --tags" - nhưng ... 'git fetch' không phải là superset của 'git fetch --tags' vì vậy mối quan hệ không hoàn toàn giống nhau ...?
davidA

9
Chỉ cần tìm thấy câu hỏi này ... tốt, đối với tôi, git pullkhông nhận được tất cả các thẻ mà chỉ có thể truy cập được từ các chi nhánh hiện tại. Tuy nhiên, git pull --tagstìm nạp tất cả các thẻ và rõ ràng là tương đương với git fetch --tags.
Archimedix

2
git fetch upstream --tags

chỉ hoạt động tốt, nó sẽ chỉ nhận được các thẻ mới và sẽ không nhận được bất kỳ cơ sở mã nào khác.


1
upstreamthường được gọi là origin. Tôi nghĩ upstreamlà một cái tên được sử dụng bởi GitHub. Trong mọi trường hợp, tên để sử dụng là tên được hiển thị bởi git remote.
Fabio nói Phục hồi lại
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.