Làm thế nào để THỰC SỰ hiển thị nhật ký của các tập tin được đổi tên bằng git?


132

Tôi còn khá mới với git, tôi đã sử dụng Subversion trước đây.

Tôi nhận thấy rằng hầu hết các plugin git đồ họa và các plugin IDE dường như không thể hiển thị lịch sử của tệp nếu tệp đã được đổi tên. Khi tôi sử dụng

git log --follow

trên dòng lệnh, tôi có thể thấy toàn bộ nhật ký đổi tên.

Theo Linus Torvalds , công tắc --follow là một thú vui "SVN noob", người dùng git nghiêm túc không sử dụng nó:

--follow là một bản hack hoàn toàn, có nghĩa là chỉ làm hài lòng người dùng cũ SVN, những người chưa bao giờ biết bất cứ điều gì về những thứ như cha mẹ hoặc đồ thị sửa đổi tốt đẹp nào.

Nó không hoàn toàn cơ bản, nhưng việc triển khai "--follow" hiện tại thực sự là một điều tiền xử lý nhanh chóng được đưa vào logic đi bộ sửa đổi, thay vì là bất cứ điều gì thực sự tách rời.

Nó thực sự được thiết kế như một thú vui "SVN noob", không phải là một thứ "chức năng git thực sự". Ý tưởng là bạn sẽ thoát khỏi suy nghĩ (tan vỡ) khi nghĩ rằng đổi tên vật chất trong bức tranh lớn.

Câu hỏi của tôi : Làm thế nào để những người dùng khó tính trong số bạn có được lịch sử của một tập tin khi nó được đổi tên? Cách 'thực sự' để làm điều này là gì?


17
@ David Hall: git mv oldfile newfilekhông gây đổi tên được ghi lại ở tất cả - nó chỉ giống như xóa một tập tin và thêm khác. git chỉ hoạt động đổi tên và sao chép từ trạng thái của cây tại mỗi lần xác nhận sau khi thực tế.
Mark Longair

20
@David Hall: Nếu bạn đổi tên tệp bằng một công cụ khác ngoài git (ví dụ /bin/mv oldfile newfile), nhưng sau đó git add newfile; git rm oldfile, kết quả không thể phân biệt được với git mv oldfile newfile.
Mark Longair

1
Hệ tư tưởng này sụp đổ nếu bạn từng chuyển một tập tin sang một kho lưu trữ mới, trong trường hợp đó, việc không thể di chuyển toàn bộ lịch sử của nó có thể là một vấn đề lớn. Mặc dù tất nhiên có những giới hạn đối với bao nhiêu lịch sử thực sự có thể đi kèm với một tệp trong một dự án phức tạp.
Roman Starkov

1
Lưu ý: git log --followcải thiện một chút với git 2.9 (tháng 6 năm 2016): xem câu trả lời của tôi bên dưới
VonC

1
Kể từ v2.15, bạn có thể muốn thử nghiệm --color-movedkhi bạn diff.
Michael - Clay Shirky

Câu trả lời:


71

Tôi nghĩ rằng động lực chung đằng sau điểm Linus là - và lấy thứ này bằng một nhúm muối - những người dùng git khó tính không bao giờ quan tâm đến lịch sử của một "tập tin". Bạn đặt nội dung vào kho lưu trữ git vì toàn bộ nội dung có một lịch sử có ý nghĩa.

Đổi tên tệp là một trường hợp đặc biệt nhỏ của "nội dung" di chuyển giữa các đường dẫn. Bạn có thể có một chức năng di chuyển giữa các tệp mà người dùng git có thể theo dõi với chức năng "pickaxe" (ví dụ log -S).

Các thay đổi "đường dẫn" khác bao gồm kết hợp và chia nhỏ tệp; git không thực sự quan tâm tập tin nào bạn xem xét đã đổi tên và tập tin nào bạn xem là đã sao chép (hoặc đổi tên và xóa) nó chỉ theo dõi nội dung đầy đủ của cây của bạn.

git khuyến khích tư duy "toàn cây" trong đó có nhiều hệ thống kiểm soát phiên bản rất tập trung vào tập tin. Đây là lý do tại sao git đề cập đến "đường dẫn" thường xuyên hơn so với "tên tệp".


Xin chào Charles, Cảm ơn câu trả lời của bạn. Có vẻ như tôi sử dụng git rất giống với cách tôi sử dụng SVN. Mặc dù tôi hiểu rằng git rất khác so với các hệ thống kiểm soát phiên bản khác, nhưng nhiều khái niệm trong git có vẻ lạ đối với tôi ... Tôi có lẽ nên hoàn thành cuốn sách git mà tôi đã mua gần đây.
Mike

24
Quan điểm của Linus là một gui "phù hợp" sẽ có thể theo dõi các đoạn mã trên các tệp và anh ta hy vọng chúng ta sẽ có các công cụ như vậy cho đến bây giờ. Thật không may, chúng ta vẫn không có sự xa xỉ đó và - theo dõi vẫn hữu ích.
Michael Parker

11
Có phải git thực sự cung cấp cho bạn một giải pháp khác hơn --followcho việc này?
Griwes

13
Tôi sẽ lập luận rằng tư duy "toàn cây" được tăng cường bằng cách --followmặc định. Ý tôi là khi tôi muốn xem lịch sử của mã trong một tệp, tôi thực sự không quan tâm đến việc tệp có được đổi tên hay không, tôi chỉ muốn xem lịch sử của mã, bất kể đổi tên. Vì vậy, theo tôi, nó có ý nghĩa --followlà mặc định vì tôi không quan tâm đến các tệp riêng lẻ; --followgiúp tôi bỏ qua các đổi tên tập tin cá nhân, thường không quan trọng.
Được chỉnh sửa

2
Vậy ... nếu tôi quyết định quan tâm đến "nội dung" thay vì tệp, làm cách nào để in các cam kết liên quan đến nội dung hiện có trong tệp này? Tôi sẽ rất vui nếu git theo dõi tất cả các tệp khác nhau cho tôi và báo cáo nhật ký của tất cả các thay đổi - Tôi chỉ không thấy cách lấy nó.
Ed Avis

36

Tôi có chính xác cùng một vấn đề mà bạn đang phải đối mặt. Mặc dù tôi không thể trả lời bạn, tôi tin rằng bạn có thể đọc email này Linus đã viết lại vào năm 2005, nó rất phù hợp và có thể cho bạn một gợi ý về cách xử lý vấn đề:

Tôi đang tuyên bố rằng bất kỳ SCM nào cố gắng theo dõi đổi tên về cơ bản đều bị phá vỡ trừ khi nó làm như vậy vì lý do nội bộ (nghĩa là cho phép deltas hiệu quả), chính xác là vì việc đổi tên không thành vấn đề. Họ không giúp bạn, và họ không những gì bạn đã quan tâm nào .

Điều quan trọng là tìm kiếm "nơi này đã đến từ đâu" và kiến ​​trúc git thực sự làm điều đó rất tốt - tốt hơn nhiều so với bất kỳ điều gì khác ngoài đó. Giáo dục

Tôi thấy nó được tham chiếu bởi bài đăng trên blog này, cũng có thể hữu ích cho bạn để tìm một giải pháp khả thi:

Trong tin nhắn, Linus đã phác thảo cách một hệ thống theo dõi nội dung lý tưởng có thể cho phép bạn tìm cách một khối mã đi vào hình dạng hiện tại. Bạn sẽ bắt đầu từ khối mã hiện tại trong một tệp, quay lại lịch sử để tìm cam kết đã thay đổi tệp. Sau đó, bạn kiểm tra sự thay đổi của cam kết để xem liệu khối mã bạn quan tâm có bị sửa đổi hay không, vì một cam kết thay đổi tệp có thể không chạm vào khối mã bạn quan tâm, nhưng chỉ một số phần khác của tập tin.

Khi bạn thấy rằng trước khi cam kết, khối mã không tồn tại trong tệp, bạn kiểm tra cam kết sâu hơn. Bạn có thể thấy rằng đó là một trong nhiều tình huống có thể xảy ra, bao gồm:

  1. Các cam kết thực sự giới thiệu khối mã. Tác giả của cam kết là người phát minh ra tính năng tuyệt vời mà bạn đang tìm kiếm nguồn gốc của nó cho (hoặc bên có tội đã giới thiệu lỗi); hoặc là
  2. Khối mã không tồn tại trong tệp, nhưng năm bản sao giống hệt của nó tồn tại trong các tệp khác nhau, tất cả đều biến mất sau khi xác nhận. Tác giả của mã được sao chép lại được tái cấu trúc bằng cách giới thiệu một hàm trợ giúp duy nhất; hoặc là
  3. (như một trường hợp đặc biệt) Trước khi cam kết, tệp hiện chứa khối mã mà bạn quan tâm không tồn tại, nhưng một tệp khác có nội dung gần giống nhau đã tồn tại và khối mã bạn quan tâm, cùng với tất cả các nội dung khác trong tệp tồn tại trước đó, đã tồn tại trong tệp khác đó. Nó đã biến mất sau khi cam kết. Tác giả của cam kết đã đổi tên tệp trong khi cung cấp cho nó một sửa đổi nhỏ.

Trong git, công cụ theo dõi nội dung cuối cùng của Linus chưa tồn tại theo kiểu hoàn toàn tự động. Nhưng hầu hết các thành phần quan trọng đã có sẵn.

Xin vui lòng, giữ cho chúng tôi đăng về tiến trình của bạn về điều này.


Cảm ơn đã đăng những bài viết đó. Mãi cho đến khi tôi đọc chúng, tôi mới hoàn toàn nắm bắt được ý tưởng về lịch sử nội dung! Tôi đã nghĩ về điều này sai cách!
DavidG

Email từ Linus rất tuyệt, cảm ơn vì đã đăng bài này.
mik01aj

Thực tế thú vị, Git v2.15 thêm--color-moved một động thái hướng tới "hệ thống theo dõi lý tưởng" đó. Tôi đã chơi với nó để xem nó theo dõi các dòng di chuyển trong một tệp, nhưng vô tình nhận ra rằng nó theo dõi các dòng di chuyển trong toàn bộ diff.
Michael - Clay Shirky

2
Linus giải thích một tình huống phức tạp. Nhưng ở đây chúng ta có một tình huống đơn giản: một tệp vừa được đổi tên (hoặc được chuyển sang thư mục khác). Do đó cần có một giải pháp đơn giản. Tôi nghĩ rằng vấn đề xuất phát từ thực tế hơn là trái ngược với Subversion, người dùng không thể hướng dẫn Git tại thời điểm cam kết nơi tệp đến và điều đó --followcó thể sai (ví dụ: nếu 2 tệp có cùng nội dung hoặc nếu có sửa đổi ngoài việc di chuyển tập tin).
vinc17

13

Tôi nhận thấy rằng hầu hết các plugin git đồ họa và các plugin IDE dường như không thể hiển thị lịch sử của tệp nếu tệp đã được đổi tên

Bạn sẽ rất vui khi biết rằng một số công cụ UI Git phổ biến hiện hỗ trợ điều này. Có hàng tá công cụ UI Git có sẵn vì vậy tôi sẽ không liệt kê tất cả, nhưng ví dụ:

  • SourceTree, khi xem nhật ký tệp, có hộp kiểm "Theo dõi các tệp đã đổi tên" ở phía dưới bên trái
  • TortoiseGit có hộp kiểm "theo dõi đổi tên" trên cửa sổ nhật ký ở phía dưới bên trái.

Thông tin thêm về các công cụ Git UI:


Nguồn hoạt động tuyệt vời khi đổi tên một lần, khi đổi tên hai lần, thay đổi chi tiết không có sẵn cho các cam kết trước khi đổi tên. Tôi đã báo cáo lỗi tại đây: jira.atlassian.com/browse/SRCTREE-5715
Intel

gitk hoạt động tuyệt vời ngay cả khi một tệp được đổi tên hai lần trong lịch sử. Lệnh này trông giống như "gitk - đường dẫn / đến / tệp" này
Intel

6

Lưu ý: git 2.9 (tháng 6 năm 2016) sẽ cải thiện khá nhiều tính chất "lỗi" của git log --follow:

Xem cam kết ca4e3ca (30 tháng 3 năm 2016) bởi SZEDER Gábor ( szeder) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 26effb8 , ngày 13 tháng 4 năm 2016)

diffcore: sửa thứ tự lặp của các tệp giống nhau trong khi phát hiện đổi tên

Nếu hai đường dẫn ' dir/A/file' và ' dir/B/file' có nội dung giống hệt nhau và thư mục mẹ được đổi tên, ví dụ ' git mv dir other-dir', thì diffcorebáo cáo các đổi tên chính xác sau:

renamed:    dir/B/file -> other-dir/A/file
renamed:    dir/A/file -> other-dir/B/file

(lưu ý đảo ngược ở đây: B/file -> A/fileA/file -> B/file)

Mặc dù về mặt kỹ thuật không sai, điều này gây nhầm lẫn không chỉ cho người dùng, mà còn cho các lệnh git đưa ra quyết định dựa trên thông tin đổi tên, ví dụ: ' git log --follow other-dir/A/file' theo sau ' dir/B/file' đổi tên.

Hành vi này là tác dụng phụ của commit v2.0.0-rc4 ~ 8 ^ 2 ~ 14 ( diffcore-rename.c: đơn giản hóa việc tìm kiếm tên chính xác, 2013-11-14): các nguồn lưu trữ hashmap trả về các mục từ cùng một nhóm, tức là các nguồn khớp với đích hiện tại , theo thứ tự LIFO.
Do đó, lần lặp đầu tiên kiểm tra ' other-dir/A/file' và ' dir/B/file' và, khi tìm thấy nội dung và tên cơ sở giống hệt nhau, báo cáo một sự đổi tên chính xác.


2

Trên Linux, tôi đã xác minh rằng SmartGit và GitEye có thể theo dõi các đổi tên khi theo dõi lịch sử của một tệp cụ thể. Tuy nhiên, không giống như gitk và GitEye, SmartGit hiển thị chế độ xem tệp và kho lưu trữ riêng biệt (chứa cấu trúc thư mục nhưng không có danh sách các tệp có trong)

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.