7

From time to time it happens that I want to re-add 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?

Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
musicmatze
  • 4,124
  • 7
  • 33
  • 48

1 Answers1

12

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, &regmatch, 0);
...
-    hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 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.

Community
  • 1
  • 1
Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
  • Just some additional info, if you want to search the case-insensitive string in one specific file: git log -i --oneline -G somestr* fileName – MadHatter Nov 16 '21 at 06:22