Tworząc 'git log' ignorujesz zmiany dla pewnych ścieżek

121

Jak mogę git logpokazać tylko zmiany, które zmieniły pliki inne niż te, które określę?

Dzięki temu git logmogę filtrować zmiany, które widzę, do tych, które dotykają danego zestawu ścieżek. To, czego chcę, to odwrócić ten filtr, aby tylko zatwierdzić te ścieżki dotykania inne niż określone.

Mogę dostać to, czego chcę

git log --format="%n/%n%H" --name-only | ~/filter-log.pl | git log --stdin --no-walk

gdzie filter-log.pljest:

#!/usr/bin/perl
use strict;
use warnings;

$/ = "\n/\n";
<>;

while (<>) {
    my ($commit, @files) = split /\n/, $_;

    if (grep { $_ && $_ !~ m[^(/$|.etckeeper$|lvm/(archive|backup)/)] } @files) {
        print "$commit\n";
    }
}

poza tym, że chcę czegoś bardziej eleganckiego.

Zauważ, że nie pytam, jak sprawić, by git ignorował pliki. Te pliki powinny być śledzone i zatwierdzane. Po prostu przez większość czasu nie jestem zainteresowany ich oglądaniem.

Powiązane pytanie: Jak odwrócić `git log --grep = <pattern>` lub Jak wyświetlić dzienniki git, które nie pasują do wzorca To to samo pytanie, z wyjątkiem komunikatów o zatwierdzeniach, a nie ścieżek.

Dyskusja na forum na ten temat z 2008 roku: Re: Wykluczanie plików z git-diff Wygląda to obiecująco, ale wątek wydaje się wysychać.

Anonymoose
źródło
Nie jestem pewien, czy istnieje wbudowany sposób, a twoje rozwiązanie w Perlu wygląda całkiem przyzwoicie. Jeśli zmodyfikujesz go, aby zaakceptować ścieżki jako argumenty wiersza poleceń, możesz po prostu utworzyć alias podobny do tego !f() { git log ... | path/to/filter-log.pl "$@" | git log --stdin --no-walk; f, lub nawet zawinąć tę część potoku do skryptu.
Cascabel
Aby obejść ten problem, używam finddo odfiltrowywania katalogów, których zatwierdzeń nie chcę widzieć. Gdybym chciał zignorować wpisy dziennika dotyczące zatwierdzeń dokonanych w katalogu głównym SiteConfig, powiedziałbym:git log `find . -type d -mindepth 1 -maxdepth 1 ! -name *SiteConfig`
Noah Sussman
Dla Git 1.9 / 2.0 (Q1 2014), zobacz moją odpowiedź poniżej : git log --oneline --format=%s -- . ":!sub"będzie działać (z magią pathspec :(exclude)i jej krótką formą:! )
VonC

Odpowiedzi:

214

Jest zaimplementowany teraz (git 1.9 / 2.0, Q1 2014) z wprowadzeniem do pathspec magic :(exclude)i jej krótką formą:! w commit ef79b1f i commit 1649612 przez Nguyễn Thái Ngọc Duy ( pclouds) , dokumentację można znaleźć tutaj .

Teraz możesz rejestrować wszystko oprócz zawartości podfolderów:

git log -- . ":(exclude)sub"
git log -- . ":!sub"

Możesz też wykluczyć określone elementy w tym podfolderze

  • konkretny plik:

      git log -- . ":(exclude)sub/sub/file"
      git log -- . ":!sub/sub/file"
  • dowolny plik w sub:

      git log -- . ":(exclude)sub/*file"
      git log -- . ":!sub/*file"
      git log -- . ":(exclude,glob)sub/*/file"

Możesz sprawić, że wielkość liter w wykluczeniu będzie niewrażliwa!

git log -- . ":(exclude,icase)SUB"

Jak zauważył Kenny Evitt

Jeśli używasz Gita w powłoce Bash, użyj ':!sub'lub ":\!sub"zamiast tego, aby uniknąć bash: ... event not foundbłędów


Uwaga: Git 2.13 (Q2 2017) doda synonim ^do!

Zobacz commit 859b7f1 , commit 42ebeb9 (08 lutego 2017) autorstwa Linusa Torvaldsa ( torvalds) .
(Scalone przez Junio ​​C Hamano - gitster- w zatwierdzeniu 015fba3 , 27 lutego 2017 r.)

pathspec magic: dodaj „ ^” jako alias dla „ !

Wybór „ !” na negatywną ścieżkę nie tylko nie pasuje do tego, co robimy w przypadku poprawek, ale także jest okropną postacią dla rozszerzenia powłoki, ponieważ wymaga cytowania.

Więc dodaj „ ^” jako alternatywny alias dla wykluczającego wpisu pathspec.


Zauważ, że przed Git 2.28 (Q3 2020), użycie negatywnej ścieżki ścieżki podczas zbierania ścieżek, w tym nieśledzonych w drzewie roboczym, zostało zerwane.

Zobacz commit f1f061e (05 czerwca 2020) autorstwa Elijah Newren ( newren) .
(Scalone przez Junio ​​C Hamano - gitster- w zobowiązaniu 64efa11 , 18 czerwca 2020 r.)

dir: naprawiono traktowanie zanegowanych pathspecs

Zgłoszone przez: John Millikin
Podpisane przez: Elijah Newren

do_match_pathspec()rozpoczął życie tak, jak match_pathspec_depth_1()i dla poprawności miał być tylko wezwany match_pathspec_depth(). match_pathspec_depth()została później zmieniona na match_pathspec(), więc niezmiennikiem, którego oczekujemy dzisiaj, do_match_pathspec()jest brak bezpośrednich rozmówców poza match_pathspec().

Niestety zamiar ten został utracony wraz ze zmianą nazw obu funkcji, a dodatkowe wywołania do do_match_pathspec()zostały dodane w zatwierdzeniach 75a6315f74 (" ls-files: dodaj dopasowanie pathspec dla podmodułów", 2016-10-07, Git v2.11.0-rc0 - scalanie wymienione w partia nr 11 ) i 89a1f4aaf7 (" dir: jeśli nasza ścieżka może pasować do plików w katalogu, powtórz do niej", 17.09.2019, Git v2.24.0-rc0).

Oczywiście, do_match_pathspec()miał ważną przewagę nad match_pathspec()- match_pathspec()zakodowałby flagi na stałe do jednej z dwóch wartości, a ci nowi wywołujący musieli przekazać jakąś inną wartość dla flag.

Ponadto, chociaż do_match_pathspec()bezpośrednie wywołanie było niepoprawne, prawdopodobnie nie było żadnej różnicy w obserwowalnym wyniku końcowym, ponieważ błąd oznaczał po prostu, że fill_diretory()będzie się powtarzał w niepotrzebnych katalogach.

Ponieważ kolejne sprawdzanie zgodności tej ścieżki na poszczególnych ścieżkach w katalogu spowodowałoby odfiltrowanie tych dodatkowych ścieżek, jedyną różnicą wynikającą z użycia niewłaściwej funkcji były niepotrzebne obliczenia.

Drugie z tych złych wezwań do_match_pathspec()dotyczyło - albo poprzez bezpośredni ruch, albo przez kopiowanie i edycję - w pewnej liczbie późniejszych refaktorów.

Zobacz zatwierdzenia 777b420347 (" dir: synchronizacja treat_leading_path()i read_directory_recursive()", 2019-12-19, Git v2.25.0-rc0 - merge ), 8d92fb2927 (" dir: zamień algorytm wykładniczy na liniowy", 2020-04-01, Git v2.27.0 -rc0 - scalanie wymienione w partii nr 5 ) i 95c11ecc73 ("Napraw podatny na błędy fill_directory()interfejs API; spraw, aby zwracał tylko dopasowania", 2020-04-01, Git v2.27.0-rc0 - scalanie wymienione w partii nr 5 ) .

Ostatni z nich wprowadził użycie do_match_pathspec()w pojedynczym pliku, a tym samym spowodował zwrócenie poszczególnych ścieżek, których nie powinno.

Problem z wywołaniem do_match_pathspec()zamiast wywołania match_pathspec()polega na tym, że wszelkie zanegowane wzorce, takie jak ``:! Niechciana_ścieżka '', będą ignorowane .

Dodaj nową match_pathspec_with_flags()funkcję, aby spełnić potrzeby określania specjalnych flag, przy jednoczesnym prawidłowym sprawdzaniu zanegowanych wzorców, dodaj duży komentarz powyżej, do_match_pathspec()aby zapobiec nadużywaniu go przez innych, i popraw bieżące wywołujące, do_match_pathspec()aby zamiast tego używały albo match_pathspec()lub match_pathspec_with_flags().

Ostatnia uwaga: DO_MATCH_LEADING_PATHSPECwymaga szczególnej uwagi podczas pracy z DO_MATCH_EXCLUDE.

Chodzi o DO_MATCH_LEADING_PATHSPECto, że jeśli mamy ścieżkę taką jak

*/Makefile

i sprawdzamy ścieżkę do katalogu, taką jak

src/module/component

że chcemy uznać to za dopasowanie, abyśmy ponownie przeszli do katalogu, ponieważ _might_ ma plik nazwany Makefilegdzieś poniżej.

Jednak gdy używamy wzorca wykluczenia, tj. Mamy ścieżkę podobną do

:(exclude)*/Makefile

NIE chcemy mówić, że ścieżka do katalogu taka jak

src/module/component

jest dopasowaniem (wykluczającym).

Chociaż gdzieś pod tym katalogiem może znajdować się plik o nazwie „Makefile”, mogą istnieć również inne pliki i nie możemy z góry wykluczyć wszystkich plików w tym katalogu; musimy powtórzyć, a następnie sprawdzić poszczególne pliki.

Dostosuj DO_MATCH_LEADING_PATHSPEClogikę, aby była aktywowana tylko dla dodatnich parametrów ścieżki.

VonC
źródło
7
Czy możesz zrobić wiele plików?
Justin Thomas
12
@JustinThomas Uważam (jeszcze nie przetestowano), że możesz wielokrotnie powtarzać ten wzorzec wykluczania ścieżki ":(exclude)pathPattern1" ":(exclude)pathPattern2", ignorując w ten sposób wiele folderów / plików.
VonC
7
Jeśli używasz Gita w powłoce Bash, użyj ':!sub'zamiast tego, aby uniknąć bash: ... event not foundbłędów . ":\!sub"nie działa.
Kenny Evitt
1
@KennyEvitt Dziękuję za zmianę i komentarz. Uwzględniłem to drugie w odpowiedzi, aby uzyskać lepszą widoczność.
VonC
2
Dla tych, którzy zastanawiają się, gdzie jest oficjalna dokumentacja dotycząca tej funkcjonalności, zobacz git help glossary(którą znalazłem w git help -g[który znalazłem sugerowany w git help]).
ravron
4

tl; dr: shopt -s extglob && git log !(unwanted/glob|another/unwanted/glob)

Jeśli używasz Bash , powinieneś być w stanie użyć rozszerzonej funkcji globowania, aby uzyskać tylko potrzebne pliki:

$ cd -- "$(mktemp --directory)" 
$ git init
Initialized empty Git repository in /tmp/tmp.cJm8k38G9y/.git/
$ mkdir aye bee
$ echo foo > aye/foo
$ git add aye/foo
$ git commit -m "First commit"
[master (root-commit) 46a028c] First commit
 0 files changed
 create mode 100644 aye/foo
$ echo foo > bee/foo
$ git add bee/foo
$ git commit -m "Second commit"
[master 30b3af2] Second commit
 1 file changed, 1 insertion(+)
 create mode 100644 bee/foo
$ shopt -s extglob
$ git log !(bee)
commit ec660acdb38ee288a9e771a2685fe3389bed01dd
Author: My Name <[email protected]>
Date:   Wed Jun 5 10:58:45 2013 +0200

    First commit

Możesz to połączyć z globstardziałaniem rekurencyjnym.

l0b0
źródło
7
To nie pokazuje zatwierdzeń wpływających na pliki, które już nie istnieją. Bardzo blisko i niezłe hackowanie.
Anonymoose,
-2

Możesz tymczasowo zignorować zmiany w pliku za pomocą:

git update-index --skip-worktree path/to/file

Idąc dalej, wszystkie zmiany w tych plikach będą ignorowane git status, git commit -aitd Kiedy jesteś gotowy do popełnienia tych plików, wystarczy odwrócić go:

git update-index --no-skip-worktree path/to/file

i zatwierdź jak zwykle.

rubysolo
źródło
9
Wydaje się, że dotyczy to nieco innej sytuacji. git update-index --skip-worktreenie powoduje git logfiltrowania zatwierdzeń, które zostały już wykonane.
Anonymoose,