Ghi lại thao tác sao chép tệp với Git


141

Khi tôi di chuyển một tệp trong git bằng git-mv, trạng thái cho thấy rằng tệp đã được đổi tên và ngay cả khi tôi thay đổi một số phần, nó vẫn coi là gần giống nhau (điều này tốt vì nó cho phép tôi theo dõi lịch sử của nó) .

Khi tôi sao chép một tệp, tệp gốc có một số lịch sử tôi muốn liên kết với bản sao mới.

Tôi đã thử di chuyển tệp sau đó cố gắng kiểm tra lại ở vị trí ban đầu - một khi đã di chuyển git sẽ không cho tôi kiểm tra vị trí ban đầu.

Tôi đã thử thực hiện một bản sao hệ thống tập tin và sau đó thêm tệp - git liệt kê nó dưới dạng một tệp mới.

Có cách nào để làm cho git ghi lại một hoạt động sao chép tệp theo cách tương tự như cách nó ghi lại một đổi tên / di chuyển tệp trong đó lịch sử có thể được truy trở lại tệp gốc?

Câu trả lời:


112

Git không đổi tên theo dõi cũng như sao chép theo dõi, điều đó có nghĩa là nó không ghi lại các đổi tên hoặc bản sao. Những gì nó làm thay vì đổi tên và sao chép phát hiện . Bạn có thể yêu cầu đổi tên phát hiện trong git diff(và git show) bằng cách sử dụng -Mtùy chọn, bạn có thể yêu cầu phát hiện sao chép bổ sung trong các tệp đã thay đổi bằng cách sử dụng -Ctùy chọn ( -Cngụ ý -M) và bạn có thể yêu cầu phát hiện bản sao đắt hơn trong số tất cả các tệp có --find-copies-harderhoặc -C -C(ngụ ý -C, ngụ ý -M). Xem trang chủ git-diff .

Bạn cũng có thể cấu hình git để luôn luôn làm phát hiện đổi tên bằng cách thiết lập diff.renamesmột giá trị đúng boolean (ví dụ truehay 1), và bạn có thể yêu cầu git để làm phát hiện bản sao quá bằng cách thiết lập nó để copyhoặc copies. Xem trang chủ git-config .

Kiểm tra -ltùy chọn git diffvà biến cấu hình liên quan diff.renameLimit.


Lưu ý rằng git log <pathspec>hoạt động khác nhau trong Git: ở đây <pathspec>là tập hợp các dấu phân cách đường dẫn, trong đó đường dẫn có thể là tên thư mục (phụ). Nó lọc và đơn giản hóa lịch sử trước khi đổi tên và phát hiện sao chép đi vào hoạt động. Nếu bạn muốn theo dõi tên và bản sao, hãy sử dụng git log --follow <filename>(hiện tại hơi hạn chế và chỉ hoạt động đối với một tệp).


1
@allyourcode: Bạn đang bối rối về điều gì? Để bật phát hiện sao chép theo mặc định, bạn đặt diff.renamesthành copies(ví dụ ' git config diff.renames copies'). Tôi đồng ý rằng nó là một chút phản trực giác.
Jakub Narębski

Một phần tôi dường như không thể phân tích được là "và bạn có thể yêu cầu làm theo mặc định cũng đổi tên phát hiện". Bạn có nói rằng có bốn giá trị mà diff.renames có thể sử dụng (true, 1, copy, copy) và tất cả chúng đều làm cùng một thứ không?
mã allyour

1
@allyourcode: Tôi xin lỗi, tôi đã không nhận thấy điều này. Đã sửa bây giờ, cảm ơn.
Jakub Narębski

4
@ peschü: Git sử dụng cơ sở dữ liệu đối tượng có nội dung làm kho lưu trữ. Nội dung tệp được lưu trữ trong nội dung 'blob' dưới địa chỉ băm nội dung SHA-1 (tốt, loại + chiều dài + nội dung). Điều này có nghĩa là nội dung đã cho chỉ được lưu trữ một lần. Nb. sự trùng lặp tự động này là lý do đằng sau việc tạo hệ thống sao lưu "bup", sử dụng định dạng gói git.
Jakub Narębski

1
Không giống như giải pháp bên dưới, cách này không hoạt động với theo dõi thay đổi trong phạm vi. Nhật ký Git cho phép một đối số phạm vi ( git log -L123,456:file.xyz) theo đúng tên, nhưng không phải là bản sao và bạn không thể vượt qua - theo dõi trong trường hợp đó; Ngoài ra, AFAICT, điều này không hoạt động với git đổ lỗi.
Clément

57

2020-05-19: Giải pháp sau đây có ưu điểm là không thay đổi nhật ký của tệp gốc, không tạo xung đột hợp nhất và ngắn hơn.

Bạn có thể buộc Git phát hiện lịch sử của tệp được sao chép trong ba lần xác nhận:

  • Thay vì sao chép, hãy chuyển sang một nhánh mới và di chuyển tệp đến vị trí mới của nó ở đó.
  • Thêm lại tập tin gốc ở đó.
  • Hợp nhất nhánh mới với nhánh ban đầu với tùy chọn không chuyển tiếp nhanh --no-ff.

(Tín dụng cho Raymond Chen .)


Giải pháp trước đây có bốn cam kết:

  • Thay vì sao chép, hãy chuyển sang một nhánh mới và di chuyển tệp đến vị trí mới của nó ở đó.
  • Chuyển sang nhánh ban đầu và đổi tên tập tin.
  • Hợp nhất nhánh mới vào nhánh ban đầu, giải quyết xung đột tầm thường bằng cách giữ cả hai tệp.
  • Khôi phục tên tệp gốc trong một cam kết riêng.

(Giải pháp được lấy từ https://stackoverflow.com/a/44036771/1389680 .)


7
Đơn giản, ngắn gọn, 100% ... Câu trả lời này là dịch vụ công cộng ... nâng cao mọi thứ trong tầm mắt
ptim

1
Sự khác biệt giữa moverename?
vovan

@vovan Bạn đang đề cập đến thực tế là trong bash bạn sẽ sử dụng mvcho cả hai hoạt động? Tôi đã sử dụng 'di chuyển' cho trường hợp có thể liên quan đến việc thay đổi thư mục của tệp và 'đổi tên' cho trường hợp không.
Robert Pollak

1
Tôi đã cố gắng làm theo công thức (mới) này và nó đã không hoạt động. Nó có thể hữu ích nếu bạn hiển thị các lệnh thực tế.
Greg Lindahl

@RobertPollak Tôi đã thử nhiều phiên bản khác nhau nhưng chúng không hoạt động. Bằng cách "di chuyển tập tin", ý bạn là git mv orig newgì? Bằng cách "gặt hái bản gốc", ý bạn là cp new orig && git add origgì?
ᆼ ᆺ
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.