Jak przeszukać wszystkie zatwierdzenia Git i Mercurial w repozytorium pod kątem określonego ciągu?

287

Mam repozytorium Git z kilkoma gałęziami i zwisającymi zatwierdzeniami. Chciałbym przeszukać wszystkie takie zatwierdzenia w repozytorium w poszukiwaniu określonego ciągu.

Wiem, jak uzyskać dziennik wszystkich zatwierdzeń w historii, ale nie obejmują one gałęzi ani wiszących obiektów BLOB, tylko historię HEAD. Chcę je wszystkie, aby znaleźć konkretne zatwierdzenie, które zostało zgubione.

Chciałbym również wiedzieć, jak to zrobić w Mercurial, ponieważ rozważam zmianę.

Josip
źródło

Odpowiedzi:

331

Możesz zobaczyć wiszące zatwierdzenia git log -g.

-g, --walk-reflogs
 Instead of walking the commit ancestry chain, walk reflog entries from
 the most recent one to older ones. 

Więc możesz to zrobić, aby znaleźć konkretny ciąg znaków w wiszącym komunikacie zatwierdzenia:

git log -g --grep=search_for_this

Alternatywnie, jeśli chcesz wyszukać zmiany dla określonego ciągu, możesz użyć opcji wyszukiwania kilofu, „-S”:

git log -g -Ssearch_for_this
# this also works but may be slower, it only shows text-added results
git grep search_for_this $(git log -g --pretty=format:%h)

Git 1.7.4 doda opcję -G , umożliwiając przekazanie -G <regexp>, aby dowiedzieć się, kiedy została przeniesiona linia zawierająca <regexp>, czego nie można zrobić -S. -S powie ci tylko, kiedy zmieni się łączna liczba wierszy zawierających ciąg znaków (tj. Dodanie / usunięcie ciągu).

Na koniec możesz użyć gitk do wizualizacji wiszących zatwierdzeń za pomocą:

gitk --all $(git log -g --pretty=format:%h)

Następnie użyj jego funkcji wyszukiwania, aby znaleźć zgubiony plik. Wszystkie te prace zakładają, że brakujące zatwierdzenie nie „wygasło” i zostało wyrzucone do pamięci, co może się zdarzyć, jeśli zwisają przez 30 dni i wygasają ponowne rejestrowania lub uruchamiane jest polecenie, które je wygasa.

richq
źródło
4
Być może zamiast uruchamiać polecenie „git grep” na (prawdopodobnie dużej) liczbie zatwierdzeń, które znajdowałyby wszystkie zatwierdzenia zawierające „search_for_this” gdzieś w projekcie, użyj tak zwanego wyszukiwania „kilof”, tj. Opcji „-S”, aby zalogować się do dziennika , która znajduje zatwierdzenia, które wprowadziły lub usunęły dany ciąg, lub dokładniej, gdy zmieniła się liczba wystąpień danego ciągu.
Jakub Narębski
5
Możesz podać wiele rozgałęzień lub użyć opcji „--all”, np. „Git log --grep =" string w komunikacie zatwierdzenia ”--all”
Jakub Narębski
To pozwoliło mi znaleźć zgubione zatwierdzenie na 2 dni pracy. Całkowicie uratowałem mój tyłek, dzięki!
Mike Chamberlain
2
Spotkałem niektóre sytuacje, w których miałem zatwierdzenia w mojej bazie danych, ale nie w moim logowaniu. Nie wiem, jak często to się dzieje. Próbowałem różnych mostów hg / git. Myślę, że może to również wynikać z upuszczonych skrytek. W każdym razie ten alias działa dobrze, aby przechwycić te przypadki:!git fsck --unreachable | sed -ne 's/^unreachable commit //p' | xargs git log --no-walk
dubiousjim
Uwaga: nie obejmuje przeszukiwania obiektów notatek. To jeszcze nie zostało zaimplementowane: git.661346.n2.nabble.com/…
Antony Stubbs
54

W Mercurial używasz hg log --keyworddo wyszukiwania słów kluczowych w komunikatach zatwierdzeń i hg log --userdo wyszukiwania konkretnego użytkownika. Zobacz hg help loginne sposoby ograniczenia dziennika.

Martin Geisler
źródło
36
Josip napisał, że rozważa przejście na Mercurial i chciałby również usłyszeć, jak to się tam dzieje.
Martin Geisler
1
hg log -kwyszukiwania zatwierdzają nazwy użytkownika i nazwy plików również w zestawach zmian (widzę to w komendach.py:log), co jest jedną z niewielu rzeczy, których nie rozumiem w hg. Powinny istnieć oddzielne opcje wyszukiwania w komunikatach zatwierdzania i nazwach plików. Wydaje się, że hg log --template '{desc}\n'|grepto pewny sposób.
Geoffrey Zheng
@GeoffreyZheng: są na to sposoby. Zobacz „hg help resetsets”, zwłaszcza funkcje desc (), user () i file (). Istnieją również przełączniki dziennika hg dla większości tego zachowania. Z mojego doświadczenia wynika jednak, że -k / keyword () jest zwykle najbardziej pomocnym sposobem wyszukiwania rzeczy.
Kevin Horn,
W jaki sposób można przeszukiwać rzeczywistą zawartość zatwierdzonego pliku ... różnice? Wiem, że byłoby to powolne wyszukiwanie, ale chcę przeprowadzić dokładne wyszukiwanie brakującej nazwy funkcji.
Jonathan
Och, oto jest:hg grep --all <term>
Jonathan
24

Oprócz odpowiedzi richq na temat używania git log -g --grep=<regexp>lub git grep -e <regexp> $(git log -g --pretty=format:%h): spójrz na następujące posty na blogu autorstwa Junio ​​C Hamano, obecnego opiekuna git


Podsumowanie

Zarówno git grep, jak i git log --grepzorientowane liniowo , ponieważ szukają linii pasujących do określonego wzorca.

Możesz użyć git log --grep=<foo> --grep=<bar>(lub git log --author=<foo> --grep=<bar>to wewnętrznie tłumaczy na dwa --grep), aby znaleźć zatwierdzenia, które pasują do któregoś z wzorców (niejawne LUB semantyczne).

Ze względu na to, że jest zorientowany na linię, przydatny semantyczny AND służy git log --all-match --grep=<foo> --grep=<bar>do znalezienia zatwierdzenia, które ma gdzieś zarówno dopasowanie do pierwszej linii, jak i dopasowanie do drugiej linii.

Z git grepmożna połączyć wiele wzorców (wszystkie, które muszą korzystać z -e <regexp>formularza) z --or(który jest domyślny), --and, --not, (i ). Dla grep --all-matchoznacza, że plik musi mieć linie pasujące do każdej z alternatyw.

Jakub Narębski
źródło
Hej Jakubie, czy chcesz zintegrować cytaty / streszczenia z tych postów na blogu? Wygląda teraz na jedną z odpowiedzi typu „tylko łącze”.
Nathan Tuggy,
11

Opierając się na odpowiedzi rq, zauważyłem, że ta linia robi to, co chcę:

git grep "search for something" $(git log -g --pretty=format:%h -S"search for something")

Który zgłosi identyfikator zatwierdzenia, nazwę pliku i wyświetli pasującą linię, jak poniżej:

91ba969:testFile:this is a test

... Czy ktoś zgadza się, że byłoby to fajną opcją do włączenia do standardowego polecenia git grep?

Sam Hiatt
źródło
5

Każde polecenie, które przyjmuje odwołania jako argumenty, zaakceptuje --allopcję udokumentowaną na stronie podręcznika dla git rev-list:

   --all
       Pretend as if all the refs in $GIT_DIR/refs/ are listed on the
       command line as <commit>.

Na przykład git log -Sstring --allwyświetli wszystkie commity, które wspominają stringi które są dostępne z gałęzi lub tagu (zakładam, że twoje wiszące commity są przynajmniej nazwane tagiem).

adl
źródło
3
Nie wydaje się, że tak jest w przypadku git grep, gdy --allwydaje się, że zostanie przetłumaczone na / użyte jako --all-match. Dla mnie to wygląda na błąd .. przy użyciu Git 1.7.2.3 (przy użyciu $(git rev-list --all)utworów).
niebieskawy
5

Z Mercurial robisz

$ hg grep "search for this" [file...]

Istnieją inne opcje, które zawężają zakres przeszukiwanych wersji.

Yawar
źródło
1
Podoba mi się również flagahg grep --all
Jonathan
2

Nie wiem o git, ale w Mercurial po prostu potokuję dane wyjściowe dziennika hg do jakiegoś skryptu sed / perl / cokolwiek, aby wyszukać to, czego szukasz. Możesz dostosować dane wyjściowe dziennika hg za pomocą szablonu lub stylu, aby ułatwić wyszukiwanie, jeśli chcesz.

Obejmie to wszystkie nazwane gałęzie w repozytorium. Mercurial nie ma czegoś takiego jak wiszące plamy afaik.

Kurt Schelfthout
źródło
1
Nie rozumiem, w jaki sposób ta odpowiedź odnosi się do określonego problemu.
jribeiro
3
Jest to odpowiedź na pytanie dotyczące Mercurial, o które pierwotne pytanie pyta w ostatnim akapicie.
Kurt Schelfthout,
1

Aby dodać jeszcze jedno rozwiązanie, o którym jeszcze nie wspomniano, musiałem powiedzieć, że użycie graficznego pola wyszukiwania gitga było dla mnie najprostszym rozwiązaniem. Wybierze pierwsze wystąpienie, a następne możesz znaleźć za pomocą Ctrl-G.

icarito
źródło
1

Jedno polecenie w git, że myślę, że o wiele łatwiej jest znaleźć ciąg:

git log --pretty=oneline --grep "string to search"

działa w Git 2.0.4

Adriano Rosa
źródło