Git - Sự khác biệt giữa 'giả định không thay đổi' và 'bỏ qua công việc'


450

Tôi có các thay đổi cục bộ đối với tệp mà tôi không muốn cam kết với kho lưu trữ của mình. Nó là một tệp cấu hình để xây dựng ứng dụng trên máy chủ, nhưng tôi muốn xây dựng cục bộ với các cài đặt khác nhau. Đương nhiên, tập tin luôn hiển thị khi tôi thực hiện 'trạng thái git' như một thứ gì đó sẽ được dàn dựng. Tôi muốn che giấu sự thay đổi đặc biệt này và không cam kết nó. Tôi sẽ không thực hiện bất kỳ thay đổi nào khác cho tập tin.

Sau khi đào bới xung quanh, tôi thấy 2 tùy chọn: 'giả sử không thay đổi' và 'bỏ qua công việc'. Một câu hỏi trước đây ở đây nói về họ nhưng không thực sự giải thích sự khác biệt của họ. Câu hỏi của tôi là thế này: hai lệnh khác nhau như thế nào? Tại sao ai đó sẽ sử dụng cái này hay cái kia?


1
Thông thường tôi đang sử dụng .gitignorecho các mục đích tương tự. Giải pháp này sẽ làm việc cho bạn?
samuil

45
samuil, .gitignore bỏ qua việc thêm, không thay đổi. Khi tệp đã có trong git, nó sẽ được theo dõi sự kiện nếu nó được liệt kê trong .gitignore
Grigory

nhưng không thể xóa tất cả và thêm tất cả để "làm mới" như được giải thích ở đây? stackoverflow.com/questions/7075923/ Mạnh @Grigory
Daniel Springer

2
Không nên bỏ qua tệp này, nếu tôi hiểu đúng ý của OP. Tệp phải nằm trong kho lưu trữ, nhưng những thay đổi rất cụ thể mà anh ta đã thực hiện không nên được cam kết - ít nhất là không phải bây giờ.
Simone

Câu trả lời:


666

Bạn muốn skip-worktree.

assume-unchangedđược thiết kế cho các trường hợp tốn kém để kiểm tra xem một nhóm các tệp đã được sửa đổi hay chưa; khi bạn đặt bit, git(dĩ nhiên) giả sử các tệp tương ứng với phần đó của chỉ mục chưa được sửa đổi trong bản sao làm việc. Vì vậy, nó tránh được một mớ hỗn độn của các statcuộc gọi. Bit này bị mất bất cứ khi nào mục nhập của tệp trong chỉ mục thay đổi (vì vậy, khi tệp được thay đổi ngược dòng).

skip-worktreecòn hơn thế nữa: ngay cả khi git biết rằng tệp đã được sửa đổi (hoặc cần được sửa đổi bởi một reset --hardhoặc tương tự), nó sẽ giả vờ rằng nó chưa được sử dụng, thay vào đó sử dụng phiên bản từ chỉ mục. Điều này vẫn tồn tại cho đến khi chỉ số bị loại bỏ.

Có một bản tóm tắt tốt về sự phân nhánh của sự khác biệt này và các trường hợp sử dụng điển hình ở đây: http://fallengamer.livejournal.com/93321.html .

Từ bài báo đó:

  • --assume-unchangedgiả định rằng một nhà phát triển không nên thay đổi một tập tin. Cờ này có nghĩa là để cải thiện hiệu suất cho các thư mục không thay đổi như SDK.
  • --skip-worktreesẽ hữu ích khi bạn hướng dẫn git không chạm vào một tệp cụ thể bao giờ vì các nhà phát triển nên thay đổi nó. Ví dụ: nếu kho lưu trữ chính ngược dòng lưu trữ một số tệp cấu hình sẵn sàng sản xuất và bạn không muốn vô tình cam kết thay đổi đối với các tệp đó, --skip-worktreethì chính xác là những gì bạn muốn.

3
Điều đó có ý nghĩa. Skip-worktree thực sự có vẻ là con đường để đi. Cảm ơn!
ckb

100
Một lưu ý nhỏ để tiết kiệm vài giây tìm kiếm và đọc. Để hủy --skip-worktreehiệu ứng và bỏ đặt cờ, có --no-skip-worktreetùy chọn. Hoạt động chính xác theo cùng một cách. Điều này rất hữu ích trong trường hợp một bàn tay bị trượt và các tệp sai bị gắn cờ hoặc nếu hoàn cảnh đã thay đổi và các tệp bị bỏ qua trước đó không nên bỏ qua nữa.
drdaeman

18
Để trả lời câu hỏi của riêng tôi ở trên, sự khác biệt giữa việc sử dụng --skip-worktree.git/info/excludetệp là cái trước sẽ hoạt động ngay cả đối với các tệp hiện đang được theo dõi. .git/info/exclude, như .gitignore, sẽ chỉ ngăn việc vô tình thêm các tệp không bị theo dõi vào chỉ mục, nhưng không thực hiện thay đổi đối với các tệp đã được theo dõi.
LinusR

13
Điều này có thể được đẩy đến điều khiển từ xa và được bảo tồn bởi tất cả các bản sao?
CMCDragonkai

4
Chỉ là cách sử dụng , thưa bà:git update-index --skip-worktree <file_name>
ruffin

108

Lưu ý: fallengamer đã thực hiện một số thử nghiệm vào năm 2011 (vì vậy chúng có thể bị lỗi thời), và đây là những phát hiện của anh ấy :

Hoạt động

  • Tệp được thay đổi cả trong kho lưu trữ cục bộ và ngược dòng
    git pull:
    Git duy trì các thay đổi cục bộ.
    Do đó, bạn sẽ không vô tình làm mất bất kỳ dữ liệu nào mà bạn đã đánh dấu bằng bất kỳ cờ nào.
    • Tệp có assume-unchangedcờ: Git sẽ không ghi đè tệp cục bộ. Thay vào đó, nó sẽ tạo ra xung đột và lời khuyên làm thế nào để giải quyết chúng
    • Tệp có skip-worktreecờ: Git sẽ không ghi đè tệp cục bộ. Thay vào đó, nó sẽ tạo ra xung đột và lời khuyên làm thế nào để giải quyết chúng

  • Tệp được thay đổi cả trong kho lưu trữ cục bộ và ngược dòng, cố gắng kéo bằng cách sử dụng kết quả trong một số công việc thủ công bổ sung nhưng ít nhất bạn sẽ không mất bất kỳ dữ liệu nào nếu bạn có bất kỳ thay đổi cục bộ nào.
    git stash
    git pull
    skip-worktree
    • Tệp có assume-unchangedcờ: Loại bỏ tất cả các thay đổi cục bộ mà không có khả năng khôi phục chúng. Hiệu ứng giống như ' git reset --hard'. ' git pull' Cuộc gọi sẽ thành công
    • Tệp có skip-worktreecờ: Stash sẽ không hoạt động trên skip-worktreecác tệp. ' git pull' sẽ thất bại với cùng một lỗi như trên. Nhà phát triển buộc phải đặt lại thủ công skip-worktreecờ để có thể stash và hoàn thành thất bại pull.

  • Không có thay đổi cục bộ, tệp ngược dòng đã thay đổi Cả hai cờ sẽ không ngăn bạn nhận được các thay đổi ngược dòng. Git phát hiện ra rằng bạn đã thất hứa và chọn phản ánh thực tế bằng cách đặt lại cờ.
    git pull
    assume-unchanged
    • Tệp có assume-unchangedcờ: Nội dung được cập nhật, cờ bị mất.
      ' git ls-files -v' sẽ cho thấy cờ được sửa đổi thành H(từ h).
    • Tệp có skip-worktreecờ: Nội dung được cập nhật, cờ được bảo tồn.
      ' git ls-files -v' sẽ hiển thị Scờ giống như trước pull.

  • Với tệp cục bộ đã thay đổi, Git không chạm vào tệp và phản ánh thực tế (tệp được hứa là không thay đổi thực sự đã được thay đổi) cho tệp.
    git reset --hard
    skip-worktreeassume-unchanged
    • Tệp có assume-unchangedcờ: Nội dung tệp được hoàn nguyên. Cờ được đặt lại thành H(từ h).
    • Tệp có skip-worktreecờ: Nội dung tệp còn nguyên vẹn. Cờ vẫn như cũ.

Ông bổ sung các phân tích sau đây:

  • Dường như skip-worktreeđang cố gắng hết sức để bảo vệ dữ liệu trên máy của bạn . Nhưng nó không ngăn bạn nhận được những thay đổi ngược dòng nếu nó an toàn. Cộng với git không đặt lại cờ trên pull.
    Nhưng bỏ qua reset --hardlệnh '' có thể trở thành một bất ngờ khó chịu cho một nhà phát triển.

  • Assume-unchangedcờ có thể bị mất trong pullhoạt động và những thay đổi cục bộ bên trong các tệp như vậy dường như không quan trọng đối với git.

Xem:

Ông kết luận:

Trên thực tế không có cờ nào là đủ trực quan .

  • assume-unchangedgiả định rằng một nhà phát triển không nên thay đổi một tập tin. Nếu một tập tin đã được thay đổi - thì sự thay đổi đó không quan trọng. Cờ này có nghĩa là để cải thiện hiệu suất cho các thư mục không thay đổi như SDK.
    Nhưng nếu lời hứa bị phá vỡ và một tập tin thực sự bị thay đổi, git sẽ hoàn nguyên cờ để phản ánh thực tế. Có lẽ bạn có thể có một số cờ không nhất quán trong các thư mục thường không có nghĩa là phải thay đổi.

  • Mặt khác skip-worktreerất hữu ích khi bạn hướng dẫn git không chạm vào một tệp cụ thể bao giờ. Điều đó hữu ích cho một tập tin cấu hình đã được theo dõi.
    Kho lưu trữ chính ngược dòng lưu trữ một số cấu hình sẵn sàng sản xuất nhưng bạn muốn thay đổi một số cài đặt trong cấu hình để có thể thực hiện một số thử nghiệm cục bộ. Và bạn không muốn vô tình kiểm tra các thay đổi trong tệp đó để ảnh hưởng đến cấu hình sản xuất. Trong trường hợp đó skip-worktreelàm cho cảnh hoàn hảo.


Với Git 2.25.1 (tháng 2 năm 2020), "Thực tế không có cờ nào đủ trực quan" được đề cập ở trên được làm rõ thêm:

Xem cam kết 7a2dc95 , cam kết 1b13e90 (ngày 22 tháng 1 năm 2020) bởi brian m. carlson ( bk2204) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 53a8329 , ngày 30 tháng 1 năm 2020)
( Danh sách gửi thư của Git )

doc: không cho phép người dùng cố gắng bỏ qua các tệp được theo dõi

Đã ký tắt: Jeff King
Đã ký tắt: brian m. carlson

Điều khá phổ biến là người dùng muốn bỏ qua các thay đổi đối với tệp mà Git theo dõi.

Các tình huống phổ biến cho trường hợp này là các cài đặt IDE và các tệp cấu hình, thường không được theo dõi và có thể được tạo từ các tệp được theo dõi bằng cơ chế tạo khuôn mẫu.

Tuy nhiên, người dùng tìm hiểu về các bit giả định không thay đổi và bỏ qua worktree và cố gắng sử dụng chúng để làm điều này bằng mọi cách.

Đây là vấn đề, bởi vì khi các bit này được đặt, nhiều thao tác hoạt động như người dùng mong đợi, nhưng chúng thường không giúp ích khi git checkoutcần thay thế một tệp.

Không có hành vi hợp lý trong trường hợp này, bởi vì đôi khi dữ liệu là quý giá, chẳng hạn như các tệp cấu hình nhất định và đôi khi đó là dữ liệu không liên quan mà người dùng sẽ vui lòng loại bỏ.

Vì đây không phải là cấu hình được hỗ trợ và người dùng dễ sử dụng sai các tính năng hiện có cho các mục đích ngoài ý muốn, gây ra nỗi buồn và sự nhầm lẫn chung , hãy ghi lại hành vi hiện tại và những cạm bẫy trong tài liệu để git update-indexngười dùng biết họ nên khám phá các giải pháp thay thế.

Ngoài ra, hãy cung cấp một giải pháp được đề xuất để xử lý trường hợp phổ biến của các tệp cấu hình, vì có các phương pháp nổi tiếng được sử dụng thành công trong nhiều môi trường.

Các git update-indextrang người đàn ông hiện nay bao gồm:

Người dùng thường cố gắng sử dụng các bit assume-unchangedskip-worktreebit để nói với Git để bỏ qua các thay đổi đối với các tệp được theo dõi. Điều này không hoạt động như mong đợi, vì Git vẫn có thể kiểm tra các tệp cây làm việc so với chỉ mục khi thực hiện các hoạt động nhất định. Nói chung, Git không cung cấp cách bỏ qua các thay đổi đối với các tệp được theo dõi, vì vậy các giải pháp thay thế được khuyến nghị.

Ví dụ: nếu tệp bạn muốn thay đổi là một loại tệp cấu hình, kho lưu trữ có thể bao gồm tệp cấu hình mẫu sau đó có thể được sao chép vào tên bị bỏ qua và sửa đổi. Kho lưu trữ thậm chí có thể bao gồm một tập lệnh để coi tệp mẫu là một mẫu, sửa đổi và sao chép nó tự động.

Phần cuối cùng đó là những gì tôi mô tả về trình điều khiển bộ lọc nội dung điển hình dựa trên các tập lệnh smudge / clean .


7
Nếu bạn có Skip-worktree trên một tệp và thay đổi ngược dòng, bạn sẽ nhận được "vui lòng cam kết hoặc bỏ qua" khi bạn cố gắng kéo, mặc dù trạng thái git không báo cáo tệp đã thay đổi. Làm thế nào bạn có thể tránh điều này, vì vậy những thay đổi cục bộ có thể tồn tại trong khi mọi người đang tìm kiếm xung quanh với các cài đặt sản xuất về nguồn gốc?
GreenAsJade

3
Vâng, tôi có thể xác nhận rằng bạn làm. Điều đó có nghĩa là vẫn rất khó để có một tệp cục bộ mà bạn chỉ muốn duy trì khác với nguồn gốc.
GreenAsJade

1
@GreenAsJade có vẻ cổ kính hơn. Bất kỳ cơ hội nào bạn có thể kiểm tra nó với 2.2.x?
VonC

1
@VonC, Liên kết đến "bình luận của Junio" không có trong lịch sử sửa đổi. Là này những gì bạn đã đề cập đến?
Michael - Clay Shirky ở đâu

1
@Michael Bắt tốt, cảm ơn bạn. Tôi đã đặt liên kết đó trở lại trong câu trả lời.
VonC
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.