It works well outside of git repos automatically. And can search across multiple git repos while respecting each repo's respective gitignores automatically. ripgrep also tends to be faster, although the absolute difference tends to be lower with 'git grep' than a simple 'grep -r', since 'git grep' does at least use parallelism.

There are other reasons to prefer one over the other, but are somewhat more minor.

Here's one benchmark that shows a fairly substantial difference between ripgrep and git-grep and ugrep:

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
$ git rev-parse HEAD
3b5e1590a26713a8c76896f0f1b99f52ec24e72f
$ git remote -v
origin git@github.com:torvalds/linux (fetch)
origin git@github.com:torvalds/linux (push)

$ time rg '\w{42}' | wc -l
1957843

real 0.706
user 7.110
sys 0.462
maxmem 300 MB
faults 0

$ time git grep -E '\w{42}' | wc -l
1957843

real 7.678
user 1:49.03
sys 0.729
maxmem 411 MB
faults 0

$ time ugrep -r --binary-files=without-match --ignore-files '\w{42}' | wc -l
1957841

real 10.570
user 46.980
sys 0.502
maxmem 344 MB
faults 0

$ time ag '\w{42}' | wc -l
1957806

real 3.423
user 8.288
sys 0.695
maxmem 79 MB
faults 0

$ time grep -E -r '\w{42}' ./ | wc -l
grep: ./.git/objects/pack/pack-c708bab866afaadf8b5da7b741e6759169a641b4.pack: binary file matches
grep: ./.git/index: binary file matches
1957843

real 47.441
user 47.137
sys 0.290
maxmem 4 MB
faults 0

The GNU grep comparison is somewhat unfair because it's searching a whole lot more than the other 3 tools. (Although notice that there are no additional matches outside of binary files.) But it's a good baseline and also demonstrates the experience that a lot of folks have: most just tend to compare a "smarter" grep with the "obvious" grep invocation and see that it's an order of magnitude faster.

It's also interesting that all tools agree on match counts except for ugrep ang ag. ag at least doesn't have any kind of Unicode support, so that probably explains that. (Don't have time to track down the discrepancy with ugrep to see who is to blame.)

And if you do want to search literally everything, ripgrep can do that too. Just add '-uuu':

$ time rg -uuu '\w{42}' | wc -l
1957845

real 1.288
user 8.048
sys 0.487
maxmem 277 MB
faults 0

And it still does it better than GNU grep. And yes, this is with Unicode support enabled. If you disable it, you get fewer matches and the search time improves. (GNU grep gets faster too.)

$ time rg -uuu '(?-u)\w{42}' | wc -l
1957810

real 0.235
user 1.662
sys 0.374
maxmem 173 MB
faults 0

$ time LC_ALL=C grep -E -r '\w{42}' ./ | wc -l
grep: ./.git/objects/pack/pack-c708bab866afaadf8b5da7b741e6759169a641b4.pack: binary file matches
grep: ./.git/index: binary file matches
1957808

real 2.636
user 2.362
sys 0.269
maxmem 4 MB
faults 0

Now, to be fair, '\w{42}' is a tricky regex. Searching something like a literal brings all tools down into a range where they are quite comparable:

$ time rg ZQZQZQZQZQ | wc -l
0

real 0.073
user 0.358
sys 0.364
maxmem 11 MB
faults 0
$ time git grep ZQZQZQZQZQ | wc -l
0

real 0.206
user 0.291
sys 1.014
maxmem 134 MB
faults 1
$ time ugrep -r --binary-files=without-match --ignore-files ZQZQZQZQZQ | wc -l
0

real 0.199
user 0.847
sys 0.743
maxmem 7 MB
faults 16

I realize this is beyond the scope of what you asked, but eh, I had fun.