Làm thế nào để tôi git đổ lỗi cho một dòng bị xóa?


506

git blamelà tuyệt vời cho các dòng được sửa đổi và thêm vào, nhưng làm thế nào tôi có thể tìm thấy khi một dòng tồn tại trong một cam kết cụ thể trước đó cuối cùng đã bị xóa. Tôi đang suy nghĩ bisect, nhưng tôi đã hy vọng cho một cái gì đó xử lý.

(Trước khi bạn đặt câu hỏi: trong trường hợp này, tôi chỉ làm một git log -pvà đã tìm kiếm thông qua cho các dòng mã và (a) một số thằng ngốc đã chỉ xóa dòng quan trọng trong cam kết trước đó và (b) Tôi là thằng ngốc đó.)


4
Có một phần tiếp theo với một câu trả lời làm rõ rằng git log -S<string> /path/to/filemuốn -choặc -cccũng sẽ hiển thị các phần xóa trong khi hợp nhất (xung đột)
cfi

3
Nó nên -c--cc. @Steen: Đúng, cảm ơn vì đã chỉ ra! Giám sát ngu ngốc. Chúc tôi có thể chỉnh sửa bình luận. Thêm một cái mới, sau đó xóa cái của tôi, sau đó bạn xóa cái của bạn thì quá rườm rà tôi đoán vậy :)
cfi

4
Tôi muốn git blamecó một tùy chọn để hiển thị các dòng đã bị xóa (có lẽ là văn bản gạch ngang hoặc văn bản màu đỏ) với bản sửa đổi trong đó chúng đã bị xóa.
Craig McQueen

Điều đó sẽ khó viết? Tôi không biết nhiều về nội bộ Git.
Malvolio

Câu trả lời:


636

Nếu bạn biết nội dung của dòng, đây là trường hợp sử dụng lý tưởng cho:

git log -S <string> path/to/file

trong đó cho thấy bạn cam kết giới thiệu hoặc loại bỏ một thể hiện của chuỗi đó. Cũng có những -G<regex>thứ làm điều tương tự với các biểu thức thông thường! Xem man git-logvà tìm kiếm -G-Scác tùy chọn, hoặc pickaxe (tên thân thiện cho các tính năng này) để biết thêm thông tin.

Các -Stùy chọn là thực sự được đề cập trong tiêu đề của git-blamemanpage quá, trong phần mô tả, nơi mà nó đưa ra một ví dụ sử dụng git log -S....


Rực rỡ ... chỉ là những gì tôi cần trong công việc porting này Tôi đang làm việc trên +1
jkp

37
Sau khi sử dụng Git được hơn 1 năm, tôi vẫn ngạc nhiên khi thấy Git luôn có một lệnh / tùy chọn ở đâu đó để giải quyết hầu hết mọi tình huống sử dụng mà tôi có. Cảm ơn đã chia sẻ cái này, nó chính xác là những gì tôi cần bây giờ!
Pascal Bourque

22
Phương pháp này đã làm việc cho tôi trước đây, nhưng bây giờ tôi đã thấy một trường hợp nó không tìm thấy cam kết nơi dòng bị xóa. Hóa ra dòng trong câu hỏi đã bị xóa trong một cam kết hợp nhất - điều đó có giải thích cho sự thất bại? ( git blame --reversePhương pháp tìm thấy mặc dù.)
antinome

9
@antinome Để hiển thị các cam kết từ hợp nhất, hãy sử dụng -ctùy chọn bổ sung.
yunzen

2
Tôi đã thực hiện một ctrl + f trên "-s" trên trang chủ và không tìm thấy gì. Bạn thấy nó ở đâu trên trang ?? Tôi đang sử dụng git 1.8.5.2
tạm

135

Tôi nghĩ những gì bạn thực sự muốn là

git blame --reverse START..END filename

Từ trang hướng dẫn :

Đi về phía trước lịch sử thay vì lùi. Thay vì hiển thị bản sửa đổi trong đó một dòng xuất hiện, phần này hiển thị bản sửa đổi cuối cùng trong đó một dòng đã tồn tại. Điều này đòi hỏi một loạt các sửa đổi như START..END nơi con đường đổ lỗi tồn tại trong START.

Với git blame reverse, bạn có thể tìm thấy cam kết cuối cùng mà dòng xuất hiện. Bạn vẫn cần nhận được cam kết đi sau.

Bạn có thể sử dụng lệnh sau để hiển thị nhật ký git đảo ngược. Cam kết đầu tiên được hiển thị sẽ là lần cuối cùng dòng đó xuất hiện và cam kết tiếp theo sẽ là khi nó được thay đổi hoặc xóa.

git log --reverse --ancestry-path COMMIT^..master

14
Nếu có nhiều sự hợp nhất từ ​​nhánh nơi dòng được thêm vào nhánh nơi dòng bị thiếu (hoặc bất kỳ trường hợp nào khác có nhiều đường dẫn trong dòng từ START đến END), git blame --reversesẽ hiển thị sửa đổi trước khi hợp nhất theo thời gian cuối cùng, không phải là sửa đổi trước khi hợp nhất ban đầu, nơi quyết định được đưa ra để không đưa ra dòng. Có cách nào để tìm bản sửa đổi sớm nhất trong đó dòng đã dừng tồn tại thay vì bản mới nhất không?
rakslice

2
@rakslice, vì bạn có thể sử dụng blame --reverse --first-Parent, nó tốt hơn một chút.
max630

17

Chỉ cần hoàn thành câu trả lời của Cascabel :

git log --full-history -S <string> path/to/file

Tôi đã có cùng một vấn đề như đã đề cập ở đây, nhưng hóa ra là dòng bị thiếu, bởi vì một cam kết hợp nhất từ ​​một nhánh đã được hoàn nguyên và sau đó được hợp nhất trở lại vào nó, loại bỏ dòng có vấn đề. Các --full-historyngăn chặn cờ bỏ qua những cam kết.


9

git đổ lỗi --reverse có thể giúp bạn đến gần nơi dòng bị xóa. Nhưng nó thực sự không chỉ ra bản sửa đổi nơi dòng bị xóa. Nó chỉ ra bản sửa đổi cuối cùng nơi dòng có mặt . Sau đó, nếu sửa đổi sau đây là một cam kết rõ ràng, bạn là người may mắn và bạn đã xóa bản sửa đổi. OTOH, nếu sửa đổi sau đây là một cam kết hợp nhất , thì mọi thứ có thể trở nên hơi hoang dã.

Là một phần trong nỗ lực tạo difflame, tôi đã giải quyết vấn đề này vì vậy nếu bạn đã cài đặt Python trên hộp của mình và bạn sẵn sàng thử, thì đừng chờ đợi nữa và hãy cho tôi biết nó diễn ra như thế nào.

https://github.com/eantoranz/difflame


0

Đối với những thay đổi ẩn trong cam kết hợp nhất

Hợp nhất tự động xác nhận các thay đổi của chúng bị ẩn khỏi đầu ra nhật ký Git. Cả pickaxeđổ lỗi ngược không tìm thấy sự thay đổi. Vì vậy, dòng tôi muốn đã được thêm vào và sau đó bị xóa và tôi muốn tìm sự hợp nhất đã loại bỏ nó. git log -p -- path/fileLịch sử tập tin chỉ cho thấy nó được thêm vào. Đây là cách tốt nhất tôi tìm thấy nó:

git log -p -U9999 -- path/file

Tìm kiếm thay đổi, sau đó tìm kiếm ngược lại cho "^ commit" - "^ commit" đầu tiên là cam kết nơi tập tin cuối cùng có dòng đó. "^ Cam kết" thứ hai là sau khi nó biến mất. Cam kết thứ hai có thể là cam kết loại bỏ nó. Điều -U9999này có nghĩa là hiển thị toàn bộ nội dung tệp (sau mỗi lần thay đổi tệp), giả sử các tệp của bạn là tất cả tối đa 9999 dòng.

Tìm bất kỳ sự hợp nhất có liên quan nào thông qua lực lượng vũ phu (khác nhau mỗi lần cam kết hợp nhất có thể với cha mẹ đầu tiên của nó, chạy với hàng tấn cam kết)

git log --merges --pretty=format:"git diff %h^...%h | grep target_text" HEAD ^$(git merge-base A B) | sh -v 2>&1 | less

. khi những thay đổi thực sự được hợp nhất vào dòng chính.)

Hiển thị cây Git với hai cam kết này (và rất nhiều lịch sử Git phức tạp đã bị xóa):

git log --graph --oneline A B ^$(git merge-base A B) (A là cam kết đầu tiên ở trên, B là cam kết thứ hai ở trên)

Hiển thị lịch sử của A và lịch sử của B trừ lịch sử của cả A và B.

Phiên bản thay thế (dường như hiển thị đường dẫn tuyến tính hơn là cây lịch sử Git thông thường - tuy nhiên tôi thích cây lịch sử git thông thường):

git log --graph --oneline A...B

Ba, không phải hai dấu chấm - ba dấu chấm có nghĩa là "r1 r2 --not $ (git merge-base --all r1 r2). Đây là tập hợp các cam kết có thể truy cập từ một trong r1 (bên trái) hoặc r2 (bên phải bên), nhưng không phải từ cả hai. " - nguồn: "người đàn ông gitrevutions"

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.