Câu hỏi Làm thế nào để grep (tìm kiếm) mã cam kết trong lịch sử git?


Tôi đã xóa một tập tin hoặc một số mã trong một tập tin đôi khi trong quá khứ. Tôi có thể grep trong nội dung (không phải trong thư cam kết) không?

Một giải pháp rất nghèo là grep log:

git log -p | grep <pattern>

Tuy nhiên, điều này không trả về hash băm ngay lập tức. Tôi chơi với git grep không có kết quả.


1117
2018-05-28 11:36


gốc


Các bài đăng trên blog này của Junio ​​C Hamano (git maintainer) có thể thú vị đối với bạn: * Công cụ theo dõi nội dung cuối cùng của Linus (về tìm kiếm cuốc, tức là git log -S và đổ lỗi) * [Vui đùa với "git log --grep"] [2] (tìm kiếm thư cam kết) * [Vui với "git grep"] [3] [2]: gitster.livejournal.com/30195.html [3]: gitster.livejournal.com/27674.html - Jakub Narębski
có thể trùng lặp Làm thế nào để grep git cam kết cho một từ nào đó
câu trả lời từ bản sao có thể thực sự hoạt động: stackoverflow.com/a/1340245/492 - CAD bloke
vấn đề với điều này là nó không đưa ra bất kỳ ngữ cảnh nào cho sự thay đổi .. tức là ai / khi nào - Sonic Soul


Các câu trả lời:


Để tìm kiếm cam kết Nội dung (tức là, các dòng nguồn thực tế, trái ngược với các thông điệp cam kết và các nội dung tương tự), những gì bạn cần làm là:

git grep <regexp> $(git rev-list --all)

Cập nhật: git rev-list --all | xargs git grep expression sẽ hoạt động nếu bạn gặp lỗi "Danh sách đối số quá dài"

Nếu bạn muốn giới hạn tìm kiếm cho một số subtree (ví dụ "lib / util"), bạn sẽ cần phải chuyển nó đến rev-list tiểu ban và grep cũng:

git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util

Điều này sẽ grep thông qua tất cả các văn bản cam kết của bạn cho regexp.

Lý do để vượt qua đường dẫn trong cả hai lệnh là vì rev-list sẽ trả về danh sách sửa đổi nơi tất cả các thay đổi đối với lib/util đã xảy ra, nhưng bạn cũng cần phải vượt qua grep để nó chỉ tìm kiếm lib/util.

Chỉ cần tưởng tượng kịch bản sau đây: grep có thể tìm thấy <regexp> trên các tệp khác được chứa trong cùng bản sửa đổi được trả lại bởi rev-list (ngay cả khi không có thay đổi đối với tập tin đó trên bản sửa đổi đó).

Dưới đây là một số cách hữu ích khác để tìm kiếm nguồn của bạn:

Tìm kiếm cây làm việc cho văn bản phù hợp với cụm từ thông dụng regexp:

git grep <regexp>

Tìm kiếm cây làm việc cho các dòng văn bản khớp với cụm từ thông dụng regexp1 hoặc regexp2:

git grep -e <regexp1> [--or] -e <regexp2>

Tìm kiếm cây làm việc cho các dòng văn bản khớp với cụm từ thông dụng regexp1 và regexp2, chỉ báo cáo đường dẫn tệp:

git grep -e <regexp1> --and -e <regexp2>

Tìm kiếm cây làm việc cho các tệp có dòng văn bản khớp với cụm từ thông dụng regexp1 và các dòng văn bản khớp với cụm từ thông dụng regexp2:

git grep -l --all-match -e <regexp1> -e <regexp2>

Tìm kiếm cây làm việc cho các dòng văn bản phù hợp đã thay đổi:

git diff --unified=0 | grep <pattern>

Tìm kiếm tất cả các sửa đổi cho văn bản phù hợp với cụm từ thông dụng regexp:

git grep <regexp> $(git rev-list --all)

Tìm kiếm tất cả các bản sửa đổi giữa rev1 và rev2 cho văn bản phù hợp với cụm từ thông dụng regexp:

git grep <regexp> $(git rev-list <rev1>..<rev2>)

1491
2018-05-28 13:47



Cảm ơn, hoạt động tuyệt vời! Thật đáng buồn mặc dù "$ (git rev-list --all)" là cần thiết và không có chuyển đổi thuận tiện để chỉ định tìm kiếm trong toàn bộ lịch sử của một chi nhánh. - Ortwin Gentz
Thật không may, tôi không thể làm được điều này với msysgit-1.7.4. Nó nói với tôi sh.exe": /bin/git: Bad file number. Câu trả lời của VonC cũng hoạt động với msysgit. - eckes
-bash: / usr / bin / git: Danh sách đối số quá dài - todd
Sử dụng xargs để loại bỏ danh sách đối số quá dài. git rev-list --all | xargs git grep expression - dlowe
Vâng, điều này dường như thất bại trên Windows là tốt, than ôi. - mlissner


Bạn nên sử dụng cái cuốc (-S) tùy chọn của git log

Tìm kiếm cho Foo:

git log -SFoo -- path_containing_change 
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change

Xem Lịch sử Git - tìm dòng bị mất theo từ khóa để biết thêm.


Như Jakub Narębski đã nhận xét:

  • điều này tìm những khác biệt giới thiệu hoặc xóa một phiên bản <string>.
    Nó thường có nghĩa là "sửa đổi nơi bạn thêm vào hoặc loại bỏ dòng với 'Foo'".

  • các --pickaxe-regex tùy chọn cho phép bạn sử dụng regex POSIX mở rộng thay vì tìm kiếm chuỗi.


Như Rob nhận xét, tìm kiếm này phân biệt chữ hoa chữ thường - anh ấy đã mở theo dõi câu hỏi về cách tìm kiếm phân biệt chữ hoa chữ thường.


440
2018-05-28 11:57



Cảm ơn, tôi không biết tùy chọn này. Có vẻ như đây là giải pháp tốt nhất nếu bạn quan tâm đến các thông điệp cam kết và giải pháp của Jeet là phù hợp nhất nếu bạn cần hành vi grep UNIX truyền thống của khớp dòng thuần túy. - Ortwin Gentz
@Ortwin: đã đồng ý (và tôi đã upvoted giải pháp đã chọn). các git log bit trong câu hỏi của bạn đã làm tôi bối rối;) - VonC
Kết hợp nó với -p gắn cờ để tạo ra sự khác biệt. - Sander
Có cách nào để loại trừ tất cả các thư mục phù hợp với một mẫu cụ thể bằng git log-S không? - BakaKuna
@ Anentropic bạn sẽ cần --branches --all tùy chọn để tìm kiếm tất cả các repo. - VonC


Cách yêu thích của tôi để làm điều đó là git log'S -G tùy chọn (được thêm vào trong phiên bản 1.7.4).

-G<regex>
       Look for differences whose added or removed line matches the given <regex>.

Có một sự khác biệt tinh tế giữa cách -G và -S tùy chọn xác định xem một cam kết có phù hợp hay không:

  • Các -S tùy chọn về cơ bản tính số lần tìm kiếm của bạn phù hợp trong một tệp trước và sau một lần commit. Cam kết được hiển thị trong nhật ký nếu số đếm trước và sau khác nhau. Ví dụ: điều này sẽ không hiển thị các cam kết trong đó một dòng phù hợp với tìm kiếm của bạn đã được di chuyển.
  • Với -G tùy chọn, cam kết được hiển thị trong nhật ký nếu tìm kiếm của bạn khớp với bất kỳ dòng nào đã được thêm, xóa hoặc thay đổi.

Lấy cam kết này làm ví dụ:

diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello

Vì số lần "hello" xuất hiện trong tệp giống nhau trước và sau lần commit này, nó sẽ không khớp với việc sử dụng -Shello. Tuy nhiên, vì đã có thay đổi đối với một dòng phù hợp hello, cam kết sẽ được hiển thị bằng -Ghello.


205
2017-09-14 18:34



Có cách nào để hiển thị ngữ cảnh thay đổi phù hợp trong đầu ra git log không? - Thilo-Alexander Ginkel
@ Thilo-AlexanderGinkel - Tôi thường chỉ thêm -p tùy chọn để hiển thị sự khác biệt cho từng cam kết. Sau đó, khi đăng nhập được mở trong máy nhắn tin của tôi, tôi tìm kiếm bất cứ điều gì nó là tôi đang tìm kiếm. Nếu máy nhắn tin của bạn là less còn bạn git log -Ghello -p, bạn có thể gõ /hello, nhấn Enter, Và sử dụng n và N để tìm các lần xuất hiện tiếp theo / trước đó của "hello". - Tyler Holien


Nếu bạn muốn duyệt các thay đổi mã (xem những gì thực sự đã được thay đổi với từ đã cho trong toàn bộ lịch sử), hãy patch chế độ - Tôi tìm thấy một sự kết hợp rất hữu ích của việc:

git log -p
# hit '/' for search mode
# type in the word you are searching
# if the first search is not relevant hit 'n' for next (like in vim ;) )

33
2018-04-17 08:17



Các giải pháp accepeted din't làm việc cho tôi không phải là git log-S. Điều này đã làm! - rodvlopes


tôi lấy Câu trả lời của @ Jeet và adpated nó vào Windows (nhờ câu trả lời này):

FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt

Lưu ý rằng đối với tôi, vì lý do nào đó, cam kết thực sự đã xóa regex này không xuất hiện trong đầu ra của lệnh, mà đúng hơn là một cam kết trước nó.


22
2017-11-17 09:35



+1 - và nếu bạn muốn tránh nhấn "q" sau mỗi lần tìm, hãy thêm --no-pager vào lệnh git ở cuối - cgp
Ngoài ra, tôi sẽ lưu ý rằng việc thêm vào một tệp văn bản có lợi thế nhất là hiển thị văn bản phù hợp. (thêm vào một tập tin văn bản bằng cách sử dụng >>results.txt cho những người không thạo trong Windows ... - cgp
Và tôi nghĩ cú pháp của bash là xấu xí :) - smido


Tìm kiếm ở bất kỳ sửa đổi nào, bất kỳ tệp nào:

git rev-list --all | xargs git grep <regexp>

Chỉ tìm kiếm trong một số tệp nhất định, ví dụ: tệp xml:

git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"

Các dòng kết quả sẽ trông như thế này: 6988bec26b1503d45eb0b2e8a4364afb87dde7af: bla.xml: văn bản của dòng nó tìm thấy ...

Sau đó bạn có thể nhận thêm thông tin như tác giả, ngày tháng, khác biệt bằng cách sử dụng git show:

git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af

10
2018-04-02 15:03





git log có thể là cách hiệu quả hơn để tìm kiếm văn bản trên tất cả các nhánh, đặc biệt nếu có nhiều kết quả phù hợp và bạn muốn xem các thay đổi gần đây (có liên quan) trước.

git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'

Danh sách các lệnh log này cam kết thêm hoặc xóa chuỗi tìm kiếm đã cho / regex, (thường) gần đây nhất trước. Các -p tùy chọn làm cho sự khác biệt có liên quan được hiển thị khi mẫu được thêm vào hoặc loại bỏ, vì vậy bạn có thể thấy nó trong ngữ cảnh.

Đã tìm thấy một cam kết có liên quan bổ sung thêm văn bản bạn đang tìm kiếm (ví dụ 8beeff00d), tìm các nhánh có chứa commit:

git branch -a --contains 8beeff00d

8
2018-06-23 00:38





Đối với bất cứ ai khác cố gắng làm điều này trong SourceTree, không có lệnh trực tiếp trong giao diện người dùng cho nó (như phiên bản 1.6.21.0). Tuy nhiên, bạn có thể sử dụng các lệnh được chỉ định trong câu trả lời được chấp nhận bằng cách mở Thiết bị đầu cuối cửa sổ (nút có sẵn trong thanh công cụ chính) và sao chép / dán chúng trong đó.

Lưu ý: SourceTree's Tìm kiếm xem một phần có thể làm văn bản tìm kiếm cho bạn. nhấn Ctrl + 3 để chuyển đến chế độ xem Tìm kiếm (hoặc nhấp vào tab Tìm kiếm có sẵn ở dưới cùng). Từ bên phải, hãy đặt loại Tìm kiếm thành Thay đổi tệp và sau đó nhập chuỗi bạn muốn tìm kiếm. Phương thức này có các hạn chế sau so với lệnh trên:

  1. SourceTree chỉ hiển thị cam kết có chứa từ tìm kiếm trong một trong các tệp đã thay đổi. Tìm tập tin chính xác có chứa văn bản tìm kiếm lại là một nhiệm vụ thủ công.
  2. RegEx không được hỗ trợ.

5
2017-10-01 05:51





Vì vậy, bạn đang cố gắng grep thông qua các phiên bản cũ của mã tìm kiếm để xem nơi mà một cái gì đó cuối cùng tồn tại?

Nếu tôi đã làm điều này, tôi có thể sẽ sử dụng git bisect. Bằng cách sử dụng bisect, bạn có thể chỉ định một phiên bản đã biết, một phiên bản đã biết và một kịch bản đơn giản kiểm tra xem phiên bản có tốt hay xấu (trong trường hợp này là grep để xem mã bạn đang tìm kiếm có hiện diện không ). Việc chạy này sẽ tìm thấy khi mã đã bị xóa.


2
2018-05-28 11:52



Có, nhưng "kiểm tra" của bạn có thể là một tập lệnh mà greps cho mã và trả về "true" nếu mã tồn tại và "false" nếu nó không có. - Rob Di Marco
Vâng, điều gì nếu mã là xấu trong bản sửa đổi 10, trở thành tốt trong phiên bản 11 và trở thành xấu một lần nữa trong sửa đổi 15 ... - Paolo
Tôi đồng ý với Paolo. Tìm kiếm nhị phân chỉ thích hợp cho các giá trị "đã đặt hàng". Trong trường hợp git bisect, điều này có nghĩa là tất cả các sửa đổi "tốt" đều xuất hiện trước tất cả các sửa đổi "xấu", bắt đầu từ điểm tham chiếu, nhưng giả định đó không thể thực hiện được khi tìm kiếm mã tạm thời. Giải pháp này có thể làm việc trong một số trường hợp, nhưng nó không phải là một giải pháp mục đích chung tốt. - Kent