From time to time, it happens that I want to readd some code which I removed from a repository some time ago. I always use tools like tig
to browse the history to find the commit which removed some lines.
Is there a way to find removed lines with Git? Something like git-grep
, but for commit content instead of commit messages?
If you remember some keyword, e.g., the name of a variable or function, in the removed lines, use pickaxe search as in
git log -Skeyword
or to see the deltas along with the commit messages
git log -p -Skeyword
Although -S
searches for exact string matches a la fgrep
, you can search for regex matches with -G
instead.
Note that the argument to -S
or -G
is “cuddled” with no space in between.
Documentation:
-S<string>
Look for differences that change the number of occurrences of the specified string (i.e. addition/deletion) in a file. Intended for the scripter’s use.
It is useful when you’re looking for an exact block of code (like a
struct
), and want to know the history of that block since it first came into being: use the feature iteratively to feed the interesting block in the preimage back into-S
, and keep going until you get the very first version of the block.
-G<regex>
Look for differences whose patch text contains added/removed lines that match .
To illustrate the difference between
-S<regex> --pickaxe-regex
and-G<regex>
, consider a commit with the following diff in the same file:+ return !regexec(regexp, two->ptr, 1, ®match, 0); ... - hit = !regexec(regexp, mf2.ptr, 1, ®match, 0);
While
git log -G"regexec\(regexp"
will show this commit,git log -S"regexec\(regexp" --pickaxe-regex
will not (because the number of occurrences of that string did not change).See the pickaxe entry in gitdiffcore [reproduced below] for more information.
diffcore-pickaxe: For Detecting Addition/Deletion of Specified String
This transformation limits the set of filepairs to those that change specified strings between the preimage and the postimage in a certain way.
-S<block of text>
and-G<regular expression>
options are used to specify different ways these strings are sought.
-S<block of text>
detects filepairs whose preimage and postimage have different number of occurrences of the specified block of text. By definition, it will not detect in-file moves. Also, when a changeset moves a file wholesale without affecting the interesting string, diffcore-rename kicks in as usual, and-S
omits the filepair (since the number of occurrences of that string didn’t change in that rename-detected filepair). When used with--pickaxe-regex
, treat the block of text as an extended POSIX regular expression to match, instead of a literal string.
-G<regular expression>
(mnemonic:grep
) detects filepairs whose textual diff has an added or a deleted line that matches the given regular expression. This means that it will detect in-file (or what rename-detection considers the same file) moves, which is noise. The implementation runs diff twice and greps, and this can be quite expensive.When
-S
or-G
is used without--pickaxe-all
, only filepairs that match their respective criterion are kept in the output. When--pickaxe-all
is used, if even one filepair matches their respective criterion in a changeset, the entire changeset is kept. This behavior is designed to make reviewing changes in the context of the whole changeset easier.