Git: Cách xóa tệp khỏi chỉ mục mà không xóa tệp khỏi bất kỳ kho lưu trữ nào


163

Khi bạn sử dụng

git rm --cached myfile

nó không xóa khỏi hệ thống tập tin cục bộ, đó là mục tiêu. Nhưng nếu bạn đã phiên bản và cam kết tệp, đẩy tệp vào kho lưu trữ trung tâm và kéo tệp vào kho khác trước khi sử dụng lệnh, nó sẽ xóa tệp khỏi hệ thống đó.

Có cách nào để xóa tệp khỏi phiên bản mà không xóa tệp khỏi bất kỳ hệ thống tệp nào không?

Chỉnh sửa: Làm rõ, tôi hy vọng.


Có lẽ bạn có thể mở rộng về trường hợp sử dụng của bạn. Chỉ mục là khu vực tổ chức cho lần xác nhận tiếp theo, vậy tại sao bạn muốn xóa tệp khỏi chỉ mục nếu bạn không muốn xóa tệp đó khỏi nhánh hiện tại?
CB Bailey

1
Tôi xin lỗi. Tôi muốn nói rằng myfile vì một số lý do đã được cam kết và phân phối từ lâu. Bây giờ mục tiêu là loại bỏ nó khỏi phiên bản mà không xóa nó khỏi hệ thống của mọi người. Lý do điều này xuất hiện là do tôi vô tình phiên bản một tập tin cấu hình. Tệp cấu hình là cần thiết, vì vậy tôi không muốn xóa nó khỏi các hệ thống nước ngoài.
Fletcher Moore

Tôi đã chỉnh sửa câu hỏi để rõ ràng hơn.
Fletcher Moore

3
git rm --cached sẽ không xóa tệp khỏi thư mục làm việc khác. Tập tin sẽ chỉ bị xóa nếu ai đó làm việc trong thư mục đó thực hiện thao tác kéo. Tập tin có thể dễ dàng được phục hồi với "git checkout HEAD @ {1} foo" (nếu được thực hiện ngay sau khi kéo.)
William Pursell

Câu trả lời:


119

Tôi không nghĩ rằng một cam kết Git có thể ghi lại một ý định như là dừng theo dõi tệp này, nhưng không xóa nó.

Thực hiện một ý định như vậy sẽ yêu cầu can thiệp bên ngoài Git trong bất kỳ kho lưu trữ nào hợp nhất (hoặc rebase lên) một cam kết xóa tệp.


Lưu một bản sao, áp dụng xóa, khôi phục

Có lẽ cách dễ nhất để làm là bảo người dùng xuôi của bạn lưu một bản sao của tệp, kéo phần xóa của bạn, sau đó khôi phục tệp. Nếu họ đang kéo qua rebase và đang 'thực hiện' sửa đổi tệp, họ sẽ bị xung đột. Để giải quyết các xung đột đó, hãy sử dụng git rm foo.conf && git rebase --continue(nếu cam kết xung đột có thay đổi bên cạnh các xung đột đối với tệp đã xóa) hoặc git rebase --skip(nếu cam kết xung đột chỉ thay đổi thành tệp đã xóa).

Khôi phục tệp dưới dạng không bị theo dõi sau khi rút một cam kết xóa nó

Nếu họ đã rút ra cam kết xóa của bạn, họ vẫn có thể khôi phục phiên bản trước của tệp bằng git show :

git show @{1}:foo.conf >foo.conf

Hoặc với kiểm tra git (theo nhận xét của William Pursell; nhưng hãy nhớ xóa lại khỏi chỉ mục!):

git checkout @{1} -- foo.conf && git rm --cached foo.conf

Nếu họ đã thực hiện các hành động khác kể từ khi kéo phần xóa của bạn (hoặc họ đang kéo theo rebase vào một ĐẦU tách rời), họ có thể cần một cái gì đó khác hơn @{1}. Họ có thể sử dụng git log -gđể tìm cam kết ngay trước khi họ xóa bạn.


Trong một bình luận, bạn đề cập đến việc tập tin mà bạn muốn không bị khóa, nhưng giữ lại là một loại tập tin cấu hình cần thiết để chạy phần mềm (trực tiếp ra khỏi kho lưu trữ).

Giữ tệp dưới dạng 'Mặc định' và thủ công / Tự động kích hoạt nó

Nếu việc tiếp tục duy trì nội dung của tệp cấu hình trong kho lưu trữ là không hoàn toàn không thể chấp nhận được, bạn có thể đổi tên tệp được theo dõi từ (ví dụ) foo.confthành foo.conf.defaultvà sau đó hướng dẫn người dùng của bạn cp foo.conf.default foo.confsau khi áp dụng cam kết đổi tên. Hoặc, nếu người dùng đã sử dụng một số phần hiện có của kho lưu trữ (ví dụ: tập lệnh hoặc một số chương trình khác được định cấu hình theo nội dung trong kho lưu trữ (ví dụ Makefilehoặc tương tự)) để khởi chạy / triển khai phần mềm của bạn, bạn có thể kết hợp cơ chế mặc định vào khởi chạy / quá trình triển khai:

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

Với cơ chế mặc định như vậy, người dùng sẽ có thể thực hiện một cam kết đổi tên foo.confthành foo.conf.defaultmà không phải thực hiện thêm bất kỳ công việc nào. Ngoài ra, bạn tránh phải sao chép thủ công một tệp cấu hình nếu bạn thực hiện cài đặt / kho lưu trữ bổ sung trong tương lai.

Viết lại lịch sử yêu cầu Can thiệp thủ công Dù sao đi nữa

Nếu không thể chấp nhận duy trì nội dung trong kho lưu trữ thì có khả năng bạn sẽ muốn xóa hoàn toàn nội dung đó khỏi lịch sử bằng một cái gì đó như thế git filter-branch --index-filter …. Lượng này để viết lại lịch sử, mà sẽ yêu cầu can thiệp bằng tay cho từng ngành / kho (xem phần “Phục hồi từ Upstream rebase” trong git rebase manpage ). Điều trị đặc biệt cần thiết cho tệp cấu hình của bạn sẽ chỉ là một bước khác mà người ta phải thực hiện trong khi khôi phục từ ghi lại:

  1. Lưu một bản sao của tập tin cấu hình.
  2. Phục hồi từ viết lại.
  3. Khôi phục tập tin cấu hình.

Bỏ qua nó để ngăn ngừa tái phát

Dù bạn sử dụng phương pháp nào, có lẽ bạn sẽ muốn bao gồm tên tệp cấu hình trong một .gitignoretệp trong kho lưu trữ để không ai có thể vô tình git add foo.conftrở lại (có thể, nhưng yêu cầu -f/ --force). Nếu bạn có nhiều hơn một tệp cấu hình, bạn có thể xem xét 'di chuyển' tất cả chúng vào một thư mục và bỏ qua toàn bộ (bằng cách 'di chuyển' Tôi có nghĩa là thay đổi nơi chương trình mong muốn tìm tệp cấu hình của nó và nhận người dùng (hoặc cơ chế khởi chạy / triển khai) để sao chép / di chuyển các tệp đến vị trí mới của chúng; rõ ràng bạn sẽ không muốn git mv một tệp vào một thư mục mà bạn sẽ bỏ qua).


5
Phản ứng cực kỳ kỹ lưỡng. Cảm ơn bạn!
Fletcher Moore

Câu trả lời của Tom Power, bên dưới, dường như mâu thuẫn với câu đầu tiên của bạn.
Mike S

1
@MikeS: Ảnh hưởng của --{,no-}assume-unchangedhoàn toàn cục bộ: trạng thái của nó không được ghi lại trực tiếp trong các cam kết. Nó có thể giúp ngăn kho lưu trữ thực hiện các thay đổi mới đối với tệp, nhưng nó không xóa nó khỏi kiểm soát phiên bản. Nếu bạn có thể đặt nó cho tất cả các kho lưu trữ không liên quan, có liên quan, thì nó có thể giúp ích cho tình huống của bạn, nhưng đó không phải là thứ mà bạn có thể trực tiếp đẩy + kéo / rebase vào các kho lưu trữ không liên quan, trần trụi khác (đặc biệt là các kho bạn không kiểm soát, theo nhận xét làm rõ của người hỏi ban đầu về câu hỏi: xem các hệ thống của người khác.
Chris Johnsen

1
I do not think a Git commit can record an intention like “stop tracking this file, but do not delete it”.- bây giờ có thể, vớigit rm --cached foo.conf
Nick Volynkin

1
@NickVolynkin: Không phải câu hỏi đã chỉ ra rằng điều này không phù hợp với mục đích của người hỏi: (tự động) giữ tệp xung quanh khi cam kết kết quả được kéo vào kho lưu trữ khác?
Chris Johnsen

86

Có vấn đề tương tự trong tuần này khi tôi vô tình cam kết, sau đó cố gắng xóa tệp xây dựng khỏi kho lưu trữ được chia sẻ và điều này:

http: // git yet.com/interantly/2009/02/18/temporantly-ignoring-files.html

đã làm việc tốt cho tôi và không được đề cập cho đến nay.

git update-index --assume-unchanged <file>

Để xóa tệp bạn quan tâm khỏi kiểm soát phiên bản, sau đó sử dụng tất cả các lệnh khác của bạn như bình thường.

git update-index --no-assume-unchanged <file>

Nếu bạn muốn đặt nó trở lại.

Chỉnh sửa: vui lòng xem ý kiến ​​từ Chris Johnsen và KPM, điều này chỉ hoạt động cục bộ và tệp vẫn nằm dưới sự kiểm soát phiên bản cho người dùng khác nếu họ không làm điều đó. Câu trả lời được chấp nhận đưa ra các phương pháp đầy đủ / chính xác hơn để xử lý vấn đề này. Ngoài ra một số lưu ý từ liên kết nếu sử dụng phương pháp này:

Rõ ràng là có khá nhiều cảnh báo đi kèm với điều này. Nếu bạn git thêm tệp trực tiếp, nó sẽ được thêm vào chỉ mục. Hợp nhất một cam kết với cờ này sẽ khiến việc hợp nhất không thành công một cách duyên dáng để bạn có thể xử lý thủ công.


7
Đây không phải là một câu trả lời cho vấn đề cụ thể được đề cập. Nó sẽ chỉ hoạt động cho kho lưu trữ cục bộ của riêng bạn, vì vậy mỗi người dùng phải tự làm việc này. Đó là một nỗi đau.
KPM

28

Để xóa tệp khỏi chỉ mục, sử dụng:

git reset myfile

Điều này sẽ không ảnh hưởng đến bản sao địa phương của bạn hoặc của bất kỳ ai khác.


1
resetchỉ xóa tệp khỏi chỉ mục nếu tệp không nằm trong cam kết CHÍNH hiện tại, nếu không, nó chỉ hoàn nguyên phiên bản chỉ mục về phiên bản CHÍNH hiện tại.
CB Bailey

1
Có lẽ tôi đã hiểu nhầm câu hỏi, nhưng dường như nó liên quan đến việc xóa một tệp khỏi chỉ mục mà không ảnh hưởng đến bất kỳ cam kết nào.
Armand

Như Charles đã nói, thiết lập lại không "xóa một tập tin". Nhập git giúp thiết lập lại để biết thêm.
Simon B.

4
Câu trả lời này có tiêu đề "Cách xóa tệp khỏi chỉ mục mà không xóa tệp khỏi bất kỳ kho lưu trữ nào". Mặc dù OP thực sự đã hỏi "Làm thế nào để tôi mở khóa một tệp mà không xóa bản sao cục bộ."
hewsonism

@hewsonism OP đã nói "bất kỳ hệ thống tập tin" (ngay cả trước khi chỉnh sửa).
jbobbins

19
  1. git rm --cached remove_file
  2. thêm tập tin vào gitignore
  3. git add .gitignore
  4. git commit -m "Excluding"
  5. Chúc vui vẻ ;)

1
Đây là cách dễ nhất.
Julien

15

Sau khi thực hiện git rm --cachedlệnh, hãy thử thêm myfilevào .gitignoretệp (tạo một tệp nếu nó không tồn tại). Điều này nên nói với git để bỏ qua myfile.

Các .gitignoretập tin được phiên bản, vì vậy bạn sẽ cần phải cam kết nó và đẩy nó vào kho lưu trữ từ xa.


1

Giải pháp của tôi là kéo vào bản sao làm việc khác và sau đó làm:

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

trong đó nói có được tất cả các đường dẫn tệp trong bình luận mới nhất và kiểm tra chúng từ cha mẹ của HEAD. Công việc hoàn thành.


0

Các giải pháp trên hoạt động tốt cho hầu hết các trường hợp. Tuy nhiên, nếu bạn cũng cần xóa tất cả dấu vết của tệp đó (tức là dữ liệu nhạy cảm như mật khẩu), bạn cũng sẽ muốn xóa nó khỏi toàn bộ lịch sử cam kết của mình, vì tệp vẫn có thể được truy xuất từ ​​đó.

Đây là một giải pháp loại bỏ tất cả dấu vết của tệp khỏi toàn bộ lịch sử cam kết của bạn, như thể nó chưa từng tồn tại, nhưng vẫn giữ tệp đúng vị trí trên hệ thống của bạn.

https://help.github.com/articles/remove-sensitive-data/

Bạn thực sự có thể bỏ qua bước 3 nếu bạn đang ở trong kho git cục bộ của mình và không cần thực hiện chạy khô. Trong trường hợp của tôi, tôi chỉ cần các bước 3 và 6, vì tôi đã tạo tệp .gitignore của mình và nằm trong kho lưu trữ mà tôi muốn làm việc.

Để xem các thay đổi của bạn, bạn có thể cần phải đi đến thư mục gốc GitHub của kho lưu trữ của bạn và làm mới trang. Sau đó điều hướng qua các liên kết để đến một cam kết cũ đã từng có tệp, để thấy rằng nó đã bị xóa. Đối với tôi, chỉ cần làm mới trang cam kết cũ không cho thấy sự thay đổi.

Nó trông đáng sợ lúc đầu, nhưng thực sự, rất dễ dàng và làm việc như một cơ duyên! :-)

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.