Jak grepować różnice git?

81

Czy istnieje sposób pokazania git-diff przefiltrowanego przez dany wzorzec.

Coś jak

git grepdiff pattern

changed file
+++ some sentence with pattern
changed file 2
--- some other pattern

Niestety najprostsze rozwiązanie nie wystarczy

git diff | grep pattern 

+++ some sentence with pattern
--- some other pattern
# not an option as doesn't put the filename close to the match

Przyszedłem z obejściem przy użyciu awk

git diff | awk "/\+\+\+/{f = \$2}; /PATTERN/ {print f \$0} "

Ale chciałbym się dowiedzieć, że jest na to polecenie.

Kuba
źródło
3
Najwyraźniej projekt github o nazwie git-diff-grep robi coś zupełnie innego.
Kuba

Odpowiedzi:

99

Nie git diff -G <regex>jesteś pewien, ale czy flaga nie jest OK?

-G <wyrażenie regularne>

Look for differences whose added or removed line matches the given <regex>.
Charles B.
źródło
15
nie jest to dokładnie to, czego szukam, ponieważ chcę zobaczyć tylko linie pasujące do wzorca, a nie całą różnicę plików, które zawierają zmianę ze wzorcem
Kuba
to chyba nie ma prostszego rozwiązania niż twoje
CharlesB
Przynajmniej git diff -G jest lepszym pierwszym krokiem niż pełny różnic git.
Kuba
1
Moja wersja nie ma flagi -G. Czy został usunięty?
RedX
3
Przydatne także do sprawdzenia, których plików dotyczy wyrażenie regularne:git diff -G <regex> --raw
Raman
11

Czy próbowałeś git diff -S<string>lub git diff -G".*string.*"? Zauważ, że nie są one równoważne, zobacz dokumentację o kilofie, aby dowiedzieć się, co robi -S.

robinst
źródło
11

Inną możliwością byłoby obejrzenie całego pliku diff i wyszukanie wyniku przy użyciu zwykłych lesspoleceń (wpisz, /a następnie wzorzec).

Jeśli lessskonfigurowałeś wyświetlanie niektórych linii przed użyciem dopasowania --jump-target=N, jest to całkiem przydatne. Spróbuj tak:

PAGER="/usr/bin/less --jump-target=10" git diff

Oznacza to, że dopasowanie powinno być pokazane w linii 10 (pokazuje 9 linii kontekstu powyżej), co może wystarczyć, aby zobaczyć również nazwę pliku.

Możesz też użyć np. --jump-target=.5Aby ustawić mecz na środku ekranu.

robinst
źródło
3

Używam git log -p, który otwiera się mniej (choć konfigurowalny), którego z kolei można wyszukiwać za pomocą /. Jest też git log -S <searchword>.

chelmertz
źródło
Znam je - nie patrzę w historię, ale w aktualne zmiany robocze.
Kuba
W porządku, w takim razie można użyć tej samej metody (zacytowanej przez Robinst). Jeśli chcesz uzyskać wynik, prawdopodobnie możesz użyć dowolnej biblioteki używającej libgit2 lub gitgui / gitk.
chelmertz
1

To wykonało pracę za mnie, mam nadzieję, że komuś pomoże:

git diff | grep  -P '^\+|^\-'
petiar
źródło
1

Myślę, że twoje podejście do diffwyjścia „grep” jest najlepszym obejściem.

Możesz ulepszyć swój skrypt awk, używając seda:

colored="(^[\[[0-9;]*[a-zA-Z])"
marker="^$colored+diff"
pattern="^$colored+.*(\+|\-).*PATTERN"
git diff --color | sed -rn -e "/$marker/! H; /$marker/ ba; $ ba; b; :a; x; /$pattern/ p"
  • colored: regex, aby dopasować kolorowe linie terminala
  • marker: znacznik odpowiadający podziałowi z różnych diffporcji, linie zaczynające się od kolorowego „diff”
  • pattern: wzorzec do wyszukania, linie zaczynające się od kolorowego „+” lub „-” i zawierające „WZORZEC”

Spowoduje to wydrukowanie porcji pełnego różnicowania, z dodanym lub usuniętym WZOREM, zachowując również przydatne kolorowe wyjście.

Zauważ, że ^[in coloredpowinno być rzeczywiste, dosłowne ^[. Możesz wpisać je w bash, naciskając Ctrl+ V, Ctrl+[

Hazzard17
źródło
świetny!! dla każdego, kto próbuje to wpisać w innym miejscu niż powłoka bash (np. edytując plik .sh w IDE), musisz zamienić coś ^[podobnego, colored=$'(\e\[[0-9;]*[a-zA-Z])'a na macOS również musisz brew install gnu-sedi wymienićsed --> gsed
Anentropic
0

Oto niestandardowe narzędzie porównywania, które umożliwia grepowanie zmian (ale nie kontekstu):

Stosowanie

GIT_EXTERNAL_DIFF="mydiff --grep foo" git diff

Spowoduje to wyświetlenie tych wierszy w zmianach, które zawierają foo (w tym wiersze, w których foozniknęły z powodu wprowadzonych zmian). Zamiast niego można użyć dowolnego wzorca grep foo.

Każdy wiersz wyjściowy zaczyna się od następującego przedrostka:

filename: oldlinenum: newlinenum|

Skryptu można również używać bez rozszerzenia --grep opcji, w którym to przypadku po prostu formatuje pełny plik różnicowy (tj. Zapewnia pełny kontekst), jak opisano powyżej.

mydiff

#!/bin/bash

my_diff()
{
    diff --old-line-format="$1"':%6dn:      |-%L'     \
         --new-line-format="$1"':      :%6dn|+%L'     \
         --unchanged-line-format="$1"':%6dn:%6dn| %L' \
         $2 $3
}

if [[ $1 == '--grep' ]]
then
    pattern="$2"
    shift 2
    my_diff "$1" "$2" "$5"|grep --color=never '^[^|]\+|[-+].\+'"$pattern"'.*'
else
    my_diff "$1" "$2" "$5"
fi

exit 0
Leon
źródło
0

W systemie Windows proste rozwiązanie to:

git diff -U0 | findstr string

Jeśli chcesz grupować według nazwy pliku, użyj tego

FOR /F "usebackq delims==" %i IN (`git diff --name-only`) do git diff -U0 %~fi | findstr string
Horace
źródło
0

Korzystam z tego z wielką satysfakcją :)

grep -ri <MY_PATTERN> $(git diff 790e26393d --name-only) 
Hrishikesh
źródło