Reputation: 194
I search within a repository by git grep by this way:
git rev-list --all | xargs git grep -lP --no-index regexp
I expected that in the output there will be only revisions of files which match to regexp expression, but I recieve all revisions, even that in which matched files have not been changed. For instance, there is a file named README.md and it has been changed twice in 1 and 4 revisions. However when I search by git grep I also recived revisions of 2 and 3 where README.md has not been changed.
I tried to find some options of git grep command to do what I want, but found nothing.
Very appreciate any help!
Upvotes: 0
Views: 431
Reputation: 488223
You have yet to answer meagar's comment, but it's worth pointing out a few things anyway:
Each commit is a full snapshot of the entire source. That is, each commit contains a complete tree of all of the files. Someone ran git commit
; this froze all files in whatever form they had in the index at that time. That became the commit's snapshot.
Running git grep
makes Git search through some sort(s) of tree(s) of files, searching for files that contain regular expressions.
By giving git grep
a list of commits, you are telling it to find every match in every file of every such tree. So of course if commits A, B, and C contain files that match, Git will tell you about the files in A, B, and C.
Perhaps your goal is to take every pair of commits, and do something with them. For instance, suppose the repository has exactly three non-merge commits, A
, B
, and C
:
A <-B <-C <--master
Commit A
has no parent (it's a root commit), so for pairing purposes Git will insert an empty commit—one that has no files—in front of A
. We can call this ε. We can then have Git compare:
A
: all files are addedA
vs B
: some files are changedB
vs C
: some files are changedWe could do this manually, one pair at a time, but there is a way to automate it: git log -p
does that. In each of these change-sets, there will be some lines of some files shown. We can have git log
search these change-sets as well, using git log -S
or git log -G
.
These two searches—-S
and -G
—are similar, but not identical. -G
takes an ordinary regular expression (a la git grep
); -S
takes a string by default, but can be told that its argument is a regular expression using --pickaxe-regex
.
In general, both tell git log
that it should show the commit (at all) if the change-set contains the given expression (but see the next bit). You can therefore leave out the -p
if you're just interested in the commit itself. If you want to see the changes made by that commit, include the -p
:
git log -p -G regex
The other difference between -S
and -G
, besides that -S
takes a string by default, is that -S
looks at the count of occurrences of matches. Hence if you search for a particular word, and a patch changes the line that contains the word but doesn't add or remove the word, -G
will show the commit while -S
won't.
If you're trying to see who made some particular line(s) of some particular file(s) look the way they do, git diff
is not the right tool, but git grep
and git log
are wrong too. Instead, use git annotate
or git blame
(these are essentially the same command; see the git annotate
documentation).
Upvotes: 2
Reputation: 2981
git log -p -G regexp
You can perform a grep on the output of this since it shows the entire patch for a file&commit that has a change of your regex.
You can also use git log --cc -G regexp
and maybe should vs. what I've become used to, which is technically "patch" output. They only vary slightly.
and fwiw I typically use | grep -C 6 '^commit'
if I'm only interested in filenames & commit versions.
Upvotes: 1