git đẩy - lực lượng cho thuê so với - lực lượng


181

Tôi đang cố gắng để hiểu sự khác biệt giữa

git push --force

git push --force-with-lease

Tôi đoán là cái sau chỉ đẩy vào điều khiển từ xa nếu điều khiển từ xa không có cam kết mà chi nhánh địa phương không có ?


" chi nhánh theo dõi từ xa địa phương ". Về cơ bản có nghĩa là điều khiển từ xa phải trông giống như những gì khách hàng của bạn mong đợi nó trông như thế nào. git help pushcó các trường hợp sử dụng giải thích mục đích của nó (về cơ bản để giữ cho bạn không bỏ qua một thay đổi mà ai đó vừa đẩy lên). Điều tôi không rõ ràng với tôi là cách hoạt động của nhánh theo dõi từ xa. Nhưng có lẽ thông thường, nó sẽ cần phải nhìn chính xác như thế nào khi bạn nhìn lần trước fetchhoặc pullkhông có cam kết mới.
zzxyz

4
@zzxyz: việc triển khai thực tế --force-with-leasetương tự như hướng dẫn so sánh và trao đổi trên các CPU hiện đại: người muốn trao đổi xảy ra sẽ cung cấp giá trị mong đợi và giá trị mới. Hệ thống thực hiện trao đổi so sánh giá trị mong đợi với giá trị hiện tại thực và trao đổi khi và chỉ khi hai giá trị bằng nhau. Với git push, giá trị mong đợi là bất cứ thứ gì có trong tên theo dõi từ xa, ví dụ, git push --force-with-lease origin Xgửi của riêng bạn origin/Xcùng với giá trị mong muốn mới; originGit cho bạn biết nếu nó đã trao đổi hay không.

1
Nếu Git tại originđã trao đổi, bạn đã hoàn thành. Nếu không, bạn có thể chạy git fetch originđể chọn giá trị hiện tại mới , xử lý lại các thay đổi của mình nếu cần và chạy một phép so sánh và hoán đổi bắt buộc khác để thử lại.

Câu trả lời:


171

force ghi đè lên một chi nhánh từ xa với chi nhánh địa phương của bạn.

--force-with-leaselà một tùy chọn an toàn hơn sẽ không ghi đè lên bất kỳ công việc nào trên nhánh từ xa nếu thêm nhiều cam kết vào nhánh từ xa (bởi một thành viên khác trong nhóm hoặc đồng nghiệp hoặc những gì có bạn). Nó đảm bảo bạn không ghi đè lên ai đó hoạt động bằng cách đẩy lực.

Tôi nghĩ rằng ý tưởng chung của bạn xung quanh lệnh là chính xác. Nếu nhánh từ xa có cùng giá trị với nhánh từ xa trên máy cục bộ của bạn - bạn sẽ ghi đè lên điều khiển từ xa. Nếu nó không có cùng giá trị - nó chỉ ra một thay đổi mà người khác đã thực hiện cho chi nhánh từ xa trong khi bạn đang làm việc với mã của mình và do đó sẽ không ghi đè lên bất kỳ mã nào. Rõ ràng nếu có các cam kết bổ sung trong điều khiển từ xa thì các giá trị sẽ không giống nhau.

Tôi chỉ nghĩ --force-with-leaselà tùy chọn để sử dụng khi tôi muốn đảm bảo rằng tôi không ghi đè lên bất kỳ mã đồng đội nào. Rất nhiều đội tại công ty của tôi sử dụng --force-with-leaselàm tùy chọn mặc định cho sự không an toàn. Nó không cần thiết trong hầu hết các trường hợp nhưng sẽ giúp bạn đỡ đau đầu nếu bạn tình cờ ghi đè lên thứ gì đó mà người khác đã đóng góp từ xa.

Tôi chắc rằng bạn đã xem các tài liệu nhưng có thể có một số lời giải thích dài dòng hơn ở đây:

https://git-scm.com/docs/git-push


38

Tìm kiếm một câu trả lời rút ra từ các nguồn đáng tin cậy và / hoặc chính thức.

"So sánh và trao đổi" được đề cập bởi torek trong các bình luận và trong câu trả lời khác của ông được minh họa thêm bằng các nguồn của chính Git .

cái sau chỉ đẩy đến điều khiển từ xa nếu điều khiển từ xa không có cam kết mà chi nhánh địa phương không có?

Tính năng đó đã được giới thiệu trong cam kết này (tháng 12 năm 2013, Git v1.8.5-rc0)

--force-with-lease sẽ bảo vệ tất cả các ref từ xa sẽ được cập nhật bằng cách yêu cầu giá trị hiện tại của chúng giống với một số mặc định hợp lý, trừ khi có quy định khác;

Hiện tại, "một số mặc định hợp lý" được định nghĩa tạm thời là " giá trị của nhánh theo dõi từ xa mà chúng tôi có đối với ref của điều khiển từ xa được cập nhật " và đó là lỗi nếu chúng tôi không có nhánh theo dõi từ xa như vậy.

Vì vậy, "cho thuê" có nghĩa là:

" force-with-lease": Bạn cho rằng bạn đã thực hiện hợp đồng thuê nhà trên ref khi bạn tìm nạp để quyết định lịch sử bị từ chối là gì và bạn chỉ có thể đẩy lùi nếu hợp đồng thuê chưa bị phá vỡ.

Các nguồn vẫn đề cập đến "cas":

  • Tùy chọn này ban đầu được gọi là "cas " (cho "so sánh và trao đổi"), tên mà không ai thích vì nó quá kỹ thuật.
  • Nỗ lực thứ hai gọi nó là "lockref" (vì về mặt khái niệm giống như đẩy sau khi lấy khóa) nhưng từ "khóa" bị ghét vì nó ngụ ý rằng nó có thể từ chối đẩy bởi người khác, đó không phải là cách mà tùy chọn này hoạt động.
  • Vòng này gọi đó là "buộc phải thuê".
    Bạn cho rằng bạn đã cho thuê trên ref khi bạn tìm nạp để quyết định lịch sử bị từ chối là gì và bạn chỉ có thể đẩy lùi nếu hợp đồng thuê chưa bị phá vỡ.

Vậy: " git push --force-with-leaseso với --force"

Như tôi đã đề cập trong " push --force-with-leasetheo mặc định ", như Git 2.13 (quý 2 năm 2017) đề cập, tùy chọn này --force-with-leasecó thể bị bỏ qua nếu một quá trình nền (như những gì bạn tìm thấy trong IDE có plugin Git) chạy git fetch origin.
Trong trường hợp đó, --forcechiếm ưu thế.


29

git đẩy - lực lượng là phá hoại vì nó ghi đè lên vô điều kiện kho lưu trữ từ xa với bất cứ thứ gì có tại địa phương. lực đẩy của git không được khuyến khích mạnh mẽ vì nó có thể phá hủy các cam kết khác đã được đẩy đến một kho lưu trữ được chia sẻ. Một trong những nguyên nhân phổ biến nhất của lực đẩy là khi chúng ta buộc phải chống lại một nhánh.

Ví dụ. Chúng tôi có một dự án với một nhánh tính năng mà cả Alice và Bob sẽ làm việc. Cả hai đều sao chép kho lưu trữ này và bắt đầu công việc. Alice ban đầu hoàn thành một phần tính năng của mình và đẩy phần này lên kho lưu trữ chính. Đây là tất cả tốt và tốt. Bob cũng hoàn thành công việc của mình, nhưng trước khi đẩy nó lên, anh nhận thấy một số thay đổi đã được hợp nhất thành chủ. Muốn giữ một cái cây sạch sẽ, anh ta thực hiện một cuộc nổi loạn chống lại nhánh chủ. Tất nhiên, khi anh ta đi đẩy chi nhánh nổi loạn này, nó sẽ bị từ chối. Tuy nhiên, không nhận ra rằng Alice đã thúc đẩy công việc của mình, anh ta thực hiện một lực đẩy. Thật không may, điều này sẽ xóa tất cả các bản ghi về những thay đổi của Alice trong kho lưu trữ trung tâm.

Những gì - Force-with-cho thuê làm là từ chối cập nhật một chi nhánh trừ khi đó là trạng thái mà chúng ta mong đợi; tức là không ai cập nhật chi nhánh ngược dòng. Trong thực tế, điều này hoạt động bằng cách kiểm tra rằng ref thượng nguồn là những gì chúng ta mong đợi, bởi vì ref là băm và mã hóa ngầm chuỗi cha mẹ thành giá trị của chúng.

Đây là một bài viết tốt liên quan đến git đẩy - lực lượng và git đẩy - lực lượng với cho thuê.


2
những gì tôi không hiểu - nếu bạn nổi loạn với chủ, thì bạn có thể đẩy mà không cần --force-with-lease ? Tại sao --force-with-leasecần thiết sau khi nổi loạn với chủ?
Alexander Mills

3
@AlexanderMills có thể có một số khả năng gây ra vấn đề. Nếu bạn là người cuối cùng đẩy nó thành chủ thì không vấn đề gì nhưng có một người khác làm việc với một nhiệm vụ khác thì nó có thể gây ra vấn đề nghiêm trọng. Nói lúc đầu A - B - C là bậc thầy, Lúc đầu Alice làm cho nó A - B - C - D - E và đồng thời Bob làm cho nó A - B - C - F - G. Nếu Alice là người cuối cùng đẩy trong chủ sau khi nổi loạn A - B - C - D - E - F - G sẽ không gây ra vấn đề gì nhưng một người khác Tom cố gắng đẩy A - B - C - D - E - R cùng lúc trong thảm họa chính sẽ xảy ra !! !
Shakil

3
--forcekhông mất cam kết, nó chỉ làm mất chúng. Chúng có thể được phục hồi bằng cách băm của chúng, như trong git checkout <SHA>hoặc git reset --hard <SHA>, giả sử người bảo trì của repo từ xa không thực hiện bất kỳ hoạt động cắt tỉa hoặc cắt tỉa nào.
Keith Russell

1
"Lực đẩy của git không được khuyến khích mạnh mẽ vì nó có thể phá hủy các cam kết khác đã được đẩy đến một kho lưu trữ được chia sẻ" tuyên bố này dựa trên quan điểm mạnh mẽ. Thực hiện một động tác đẩy là một phần của quy trình đánh giá mã git rebase bình thường. Cũng như đã đề cập, bạn có thể truy xuất các cam kết ngay cả sau khi thực hiện việc này.
Étienne

9

Giả sử bất kỳ móc nhận trước nào trên máy chủ chấp nhận đẩy, điều này sẽ luôn thành công:

git push --force

Trong khi điều này chạy một kiểm tra phía khách hàng cụ thể trước khi tiến hành:

git push --force-with-lease

Bạn có thể tự chạy kiểm tra cụ thể. Đây là thuật toán "cho thuê kiểm tra":

  1. Chỉ ra chi nhánh hiện tại của bạn.

  2. Chạy đi git for-each-ref refs/remotes. Hãy lưu ý đến id xác thực mà khách hàng git của bạn nghĩ tương ứng với trạng thái ngược dòng của chi nhánh hiện tại của bạn.

Ví dụ: nếu bạn đang ở chi nhánh "foo", hãy lưu ý đến id xác thực được liên kết với "refs / điều khiển từ xa / origin / foo".

  1. Xác định id xác thực thực tế của nhánh từ xa trên máy chủ git ngược dòng ngay bây giờ.

  2. Chỉ để "git đẩy" tiến hành nếu id xác thực mà bạn trích xuất từ ​​bước 2 và bước 3 đồng ý. Nói cách khác, chỉ tiến hành nếu khái niệm ngược dòng địa phương của bạn đồng ý với thượng nguồn thực tế.

Có một hàm ý đáng buồn ở đây: vì git fetchcập nhật tất cả các ref trong "refs / remote / origin / *" lên các phiên bản mới nhất của chúng, nên tổ hợp các lệnh này về cơ bản là giống hệt git push --force:

git fetch

# The command below behaves identically to "git push --force"
# if a "git fetch" just happened!

git push --force-with-lease

Để khắc phục điểm yếu cố hữu này trong git push --force-with-leasetôi cố gắng không bao giờ chạy git fetch. Thay vào đó, tôi luôn luôn chạy git pull --rebasebất cứ khi nào tôi cần đồng bộ hóa với ngược dòng, vì git pullchỉ cập nhật một ref duy nhất theo ref / điều khiển từ xa, giữ cho "hợp đồng thuê" --force-with-leasehữu ích.


1
nếu kiểm tra là phía khách hàng, có tiềm năng cho một điều kiện cuộc đua không? tức là ai đó đẩy thay đổi sau khi kiểm tra nhưng trước khi đẩy bắt buộc?
craq

2

Buộc-cho thuê không nhất thiết phải an toàn. Nó chỉ hoạt động như Sylvie nói. Một lưu ý: Trong git, một nhánh chỉ là một con trỏ trên một cam kết. Và cam kết điểm không hoặc nhiều hơn cam kết cha mẹ. Ngay cả khi bạn thay đổi chi nhánh hoàn toàn bằng thiết lập lại git cứng và đẩy mạnh hoặc đẩy với - - buộc phải thuê mà không muốn, đó không hẳn là một vấn đề lớn. Bạn có thể sử dụng reflog git cục bộ của mình để xem mẹo địa phương của bạn trên các nhánh (lúc đó CHÍNH ở đâu?) Đã thay đổi và đặt lại và đẩy chi nhánh một lần nữa. Sau đó, bạn chỉ mất các cam kết mới trên nhánh từ xa, nhưng thậm chí chúng có thể được khôi phục bởi các thành viên trong nhóm.

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.