Tôi có thể 'git commit' một tập tin và bỏ qua những thay đổi nội dung của nó không?


355

Mỗi nhà phát triển trong nhóm của tôi có cấu hình cục bộ của riêng họ. Thông tin cấu hình đó được lưu trữ trong một tệp có tên devtargets.rbđược sử dụng trong các tác vụ xây dựng cào của chúng tôi. Mặc dù vậy, tôi không muốn các nhà phát triển ghi đè lên tệp mục tiêu của nhau.

Suy nghĩ đầu tiên của tôi là đưa tập tin đó vào .gitignoredanh sách để nó không bị git.

Sau đó, tôi bắt đầu tự hỏi: có thể cam kết tệp, nhưng bỏ qua các thay đổi đối với tệp? Vì vậy, tôi sẽ cam kết một phiên bản mặc định của tệp và sau đó khi nhà phát triển thay đổi nó trên máy cục bộ của họ, git sẽ bỏ qua các thay đổi và nó sẽ không hiển thị trong danh sách các tệp đã thay đổi khi bạn thực hiện trạng thái git hoặc cam kết git .

Điều đó có thể không? Nó chắc chắn sẽ là một tính năng tốt ...


1
Xem thêm stackoverflow.com/questions/3318043/ trên một chủ đề tương tự.
VonC


Câu trả lời:


458

Chắc chắn, tôi làm chính xác điều này theo thời gian sử dụng

git update-index --assume-unchanged [<file> ...]

Để hoàn tác và bắt đầu theo dõi lại (nếu bạn quên những tập tin nào chưa được theo dõi, hãy xem câu hỏi này ):

git update-index --no-assume-unchanged [<file> ...]

Tài liệu liên quan :

- [no-] giả sử không thay đổi
Khi cờ này được chỉ định, tên đối tượng được ghi cho đường dẫn không được cập nhật. Thay vào đó, tùy chọn này đặt / bỏ cài đặt bit "giả sử không thay đổi" cho các đường dẫn. Khi bit "giả sử không thay đổi" được bật, người dùng hứa sẽ không thay đổi tệp và cho phép Git giả định rằng tệp cây làm việc khớp với những gì được ghi trong chỉ mục. Nếu bạn muốn thay đổi tệp cây làm việc, bạn cần hủy đặt bit để báo cho Git. Điều này đôi khi hữu ích khi làm việc với một dự án lớn trên một hệ thống tệp có lstat(2)cuộc gọi hệ thống rất chậm (ví dụ: cifs).

Git sẽ thất bại (một cách duyên dáng) trong trường hợp nó cần sửa đổi tệp này trong chỉ mục, ví dụ như khi hợp nhất trong một cam kết; do đó, trong trường hợp tệp giả định không bị theo dõi bị thay đổi ngược dòng, bạn sẽ cần xử lý tình huống theo cách thủ công.

Thất bại trong trường hợp này có nghĩa là, nếu có bất kỳ thay đổi nào ngược dòng với tệp đó (thay đổi hợp pháp, v.v.) khi bạn thực hiện thao tác kéo, nó sẽ nói:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext

và sẽ từ chối hợp nhất.

Tại thời điểm đó, bạn có thể khắc phục điều này bằng cách hoàn nguyên các thay đổi cục bộ của mình, đây là một cách:

 $ git checkout filename.ext

sau đó kéo lại và sửa đổi lại tệp cục bộ của bạn hoặc có thể đặt –no-assume-unchangedvà bạn có thể thực hiện stash và hợp nhất bình thường, v.v. tại thời điểm đó.


10
lệnh này có thực hiện công việc cục bộ trong thư mục .git không? Ý tôi là, nếu tôi chạy lệnh này cho một tệp config.php, liệu điều này có lan truyền đến những người dùng khác đang sử dụng repo không?
Magus

16
@Magus: Không. Điều này sẽ chỉ hoạt động cho bạn.
Rob Wilkerson

3
Và ngay sau đó, bạn sẽ muốn biết cách xác định một tệp được giả sử không thay đổi: stackoverflow.com/questions/2363197/
Kẻ

10
Thay đổi tệp bị bỏ qua theo cách này sẽ bị mất khi sử dụng "git stash". Có cách nào xung quanh đó không?
Alexis

5
Đây không phải git update-index --assume-unchangedlà những gì cho. công khai-inbox.org / git / từ
jsageryd

97

Cách ưa thích để làm điều này là sử dụng git update-index --skip-worktree <file>, như được giải thích trong câu trả lời này :

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 (tất 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 cuộc gọi stat. 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ằng cách đặt lại - dù hay tương tự), nó sẽ giả vờ như vậy, không 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ỏ.

Để hoàn tác điều này, sử dụng git update-index --no-skip-worktree <file>

Kể từ phiên bản git 2.25.1, đây cũng không còn là cách được đề xuất, trích dẫn:

Người dùng thường cố gắng sử dụng các bit giả định không thay đổi và bỏ qua worktree để báo cho 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.


Điều này có hoạt động trên tất cả người dùng kiểm tra kho lưu trữ không? Họ sẽ nhận được một số tệp nhất định nhưng không còn có thể thêm các thay đổi, do nhầm lẫn, trừ khi nói rõ ràng như vậy?
mmm

2
@momomo cờ được lưu trữ trong chỉ mục nên không, nó chỉ dành cho một người dùng. Xem câu trả lời của erjiang cho một cái gì đó hoạt động trên tất cả người dùng.
1615903

Tôi đang cố gắng tìm hiểu nội dung của tập tin nên là gì. Tôi nhận xét về câu trả lời bạn đề cập, nhưng không có câu trả lời. Nó được đặt ở đâu và nội dung của nó là gì? Bạn có biết?
mmm

Tôi không theo dõi. Lệnh được sử dụng để bỏ qua một tệp cụ thể mà bạn chỉ định trong lệnh. Nội dung của tập tin đó không liên quan.
1615903

1
Các tài liệu Git đặc biệt nói không sử dụng git update-index --skip-worktreecho mục đích này.
bk2204

43

Thực tế phổ biến dường như là tạo devtargets.default.rbvà cam kết nó, sau đó hướng dẫn mỗi người dùng sao chép tệp đó vào devtargets.rb(nằm trong danh sách .gitignore). Ví dụ, CakePHP thực hiện tương tự cho tệp cấu hình cơ sở dữ liệu của nó, tự nhiên thay đổi từ máy này sang máy khác.


6
Bạn không thể .gitignore một tập tin đang được theo dõi. .gitignore chỉ có tác dụng đối với các tệp không có trong chỉ mục.
CB Bailey

1
tôi đã cố gắng tránh làm điều này, mặc dù tôi thực sự không có lý do chính đáng. chúng tôi đang làm điều đó ngay bây giờ và tôi nghĩ thật khó để nhớ rằng tôi cần phải tạo phiên bản của riêng mình mà không có ".default" trong tên.
Derick Bailey

11
@DerickBailey Nhưng để công bằng, việc sao chép tệp dễ dàng hơn là nhớ sử dụng --assume-unchangedtùy chọn cho tất cả những người sao chép kho lưu trữ.
Dan

1
@DerickBailey bạn cũng có thể thiết lập bản dựng cào của mình thành mặc định devtargets.default.rbnếu devtargets.rbkhông tồn tại.
Luke

@erjang có gì trong tập tin devtarget.default.rb? Một ví dụ?
mmm

2

Đối với người dùng IntelliJ IDEA: Nếu bạn muốn bỏ qua các thay đổi cho một tệp (hoặc tệp), bạn có thể di chuyển nó sang khác Change Set.

  • Trụ sở để Local Changes( Cmd + 9)
  • Chọn tập tin bạn muốn bỏ qua
  • F6 để di chuyển chúng đến nơi khác Change Set
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.