Używając Gita, pokaż wszystkie zatwierdzenia, które istnieją * tylko * w jednej określonej gałęzi, a nie * żadnych * innych

86

Mając gałąź, chciałbym zobaczyć listę zatwierdzeń, które istnieją tylko w tej gałęzi. W tym pytaniu omawiamy sposoby sprawdzenia, które zatwierdzenia znajdują się w jednej gałęzi, ale nie w jednej lub więcej określonych innych gałęzi.

To jest nieco inne. Chciałbym zobaczyć, który zobowiązuje się na jednej gałęzi, ale nie na jakichkolwiek innych branż.

Przypadek użycia dotyczy strategii rozgałęziania, w której niektóre gałęzie powinny być tylko scalane i nigdy nie zatwierdzane bezpośrednio. Byłoby to używane do sprawdzania, czy jakiekolwiek zatwierdzenia zostały wykonane bezpośrednio w gałęzi „tylko do łączenia”.

EDYCJA: Poniżej znajdują się kroki, aby skonfigurować fałszywe repozytorium git do przetestowania:

git init
echo foo1 >> foo.txt
git add foo.txt
git commit -am "initial valid commit"
git checkout -b merge-only
echo bar >> bar.txt
git add bar.txt
git commit -am "bad commit directly on merge-only"
git checkout master
echo foo2 >> foo.txt 
git commit -am "2nd valid commit on master"
git checkout merge-only 
git merge master

Powinien pojawić się tylko zatwierdzenie z komunikatem „złe zatwierdzenie bezpośrednio przy scalaniu”, które zostało wykonane bezpośrednio w gałęzi tylko do scalania.

jimmyorr
źródło
1
To pytanie zakłada, że ​​wszystkie połączone gałęzie są obecnie dostępne w repozytorium, nigdy nie są usuwane po całkowitym scaleniu, a być może nigdy nie są łączone z przewijaniem do przodu. Daj mi znać, jeśli czegoś mi brakuje, ale wydaje mi się, że działa to tylko dla stosunkowo niewielkiego zestawu dozwolonych gałęzi scalania, więc dlaczego nie użyć po prostu git log ^branch1 ^branch2 merge-only-branchskładni?
Karl Bielefeldt
1
git log ^branch1 ^branch2 merge-only-branchWymaga wymieniając się każdą gałąź. Można tego uniknąć dzięki sprytnemu użyciu bash / grep (zobacz moją odpowiedź poniżej), ale mam nadzieję, że git ma do tego wbudowaną obsługę. Masz rację, zakładając, że wszystkie gałęzie scalania są zdalne (tylko lokalne są tak dobre, jak nieistniejące dla innych programistów). Użycie --no-mergespowoduje pominięcie wszelkich zatwierdzeń, które zostały scalone, a następnie usunięto ich oryginalną gałąź typu merge-from, więc zakłada się, że gałęzie typu merge-from są zachowywane, dopóki nie zostaną scalone w gałąź non-merge-only (tj. Master).
jimmyorr

Odpowiedzi:

75

Właśnie znaleźliśmy to eleganckie rozwiązanie

git log --first-parent --no-merges

W twoim przykładzie oczywiście nadal pojawia się początkowe zatwierdzenie.

ta odpowiedź nie odpowiada dokładnie na pytanie, ponieważ początkowe zatwierdzenie wciąż się pojawia. Z drugiej strony wydaje się, że wielu przyjeżdżających tutaj ludzi znajduje odpowiedź, której szukają.

wrtsprt
źródło
1
Prosty, skuteczny, najlepszy.
Zabba
1
Ponieważ początkowe zatwierdzenie na master wciąż się pojawia, to nie odpowiada na pytanie.
jimmyorr
6
Samo to nie spełnia warunku „zatwierdzenia, które istnieją tylko w tej gałęzi” - pokazuje initial valid commit, co jest częścią obu gałęzi merge-onlyi master. Jednakże, jeśli podejmiemy wysiłek włożenia na końcu nazwy bieżącej gałęzi, po której następuje nazwa (nazwy) gałęzi z prefiksem ^, z których wynika, że ​​bieżąca gałąź się wywodzi, rozwiązuje to połowę problemów (z wyłączeniem rzeczy, które zostały scalone). Np .:git log --first-parent --no-merges merge-only ^master
Slipp D. Thompson,
13
Nie jestem pewien, dlaczego tak bardzo się nad tym głosowano, nie wydaje się to w ogóle mieć związku z pytaniem. Z pewnością nie zawiera informacji, których szukał plakat.
Chris Rasys
2
Ta odpowiedź może nie być doskonała. Ale jest to proste i na pewno działa do pewnego stopnia. Uważam, że przydatne jest dodanie nazwy gałęzi - czyli filtrowanie wszystkich zatwierdzeń należą do danej gałęzi:git log --first-parent --no-merges | grep <branch_name>
artm
29

Dzięki uprzejmości mojego drogiego przyjaciela Redmumby :

git log --no-merges origin/merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/remotes/origin |
    grep -Fv refs/remotes/origin/merge-only)

... gdzie origin/merge-onlyjest nazwa twojego zdalnego oddziału tylko do scalania. Jeśli pracujesz na lokalnym repozytorium git, zastąp refs/remotes/origingo refs/headsi zastąp nazwę zdalnego oddziału nazwą origin/merge-onlylokalnego oddziału merge-only, tj .:

git log --no-merges merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/heads |
    grep -Fv refs/heads/merge-only)
jimmyorr
źródło
2
Mam nadzieję, że ktoś inny może zapewnić rozwiązanie bez grepa, używając tylko git, ale jeśli nie, to wydaje się całkiem eleganckie.
jimmyorr
1
Tak, eleganckie. Służy git for-each-refdo wyświetlania wszystkich nazw referencyjnych w miejscu pochodzenia i grep -vdo pominięcia gałęzi tylko do scalania. git logprzyjmuje --notopcję, do której przekazujemy naszą listę wszystkich referencji (z wyjątkiem gałęzi tylko do scalania). Jeśli masz bardziej elegancką odpowiedź na problem, posłuchajmy tego.
jimmyorr
2
Och, jestem pewien, że to najbardziej elegancka odpowiedź. Twierdzę tylko, że jest to trochę „rozwlekłe / złożone” dla prawdziwej elegancji. :-) Nie chciałem dyskredytować twojego podejścia, sir!
Chris K
1
Kropka /*w git for-each-refspoleceniach polegać na nie pasujące jakiś istniejący plik i nie posiadające failgloblub nullglobzestaw ( bash opcje, inne pociski zmieniać). Należy albo zacytować / pominąć gwiazdkę, albo po prostu zostawić koniec /*( git for-each-refwzorce mogą być dopasowane „od początku do ukośnika”). Może użyj grep -Fv refs/remotes/origin/foo( refs/heads/foo), aby dokładniej określić, które odwołania są eliminowane.
Chris Johnsen
3
Można to uprościć, jeśli chcesz zobaczyć tylko zmiany obecne w jednej gałęzi, a nie w innej: git log --no-merges B1 --not B2gdzie B1 to gałąź, którą Cię interesuje, a B2 to gałąź, z którą chcesz porównać B1. Zarówno B1, jak i B2 mogą być oddziałami lokalnymi lub zdalnymi, dlatego można określić git log --no-merges master --not origin/master, a nawet określić dwa gałęzie zdalne.
pan b
21
git log origin/dev..HEAD

Spowoduje to wyświetlenie wszystkich zatwierdzeń dokonanych w Twojej gałęzi.

Prakash
źródło
2
@Prakash origin/branchNamebędzie wskazywać na głowę zdalnego oddziału ORAZ HEADwskaże na zatwierdzenie ostatniego lokalnego zatwierdzenia w tej gałęzi. Więc to nie zadziała, jeśli użyłeś git push.
Bharat,
Możesz użyć tego do porównania innego lokalnego oddziału. Flaga --no-scales może być również przydatna przy odpowiedzi na pierwotne pytanie OP.
Paul Whipp
15

Odpowiedź @Prakash działa. Dla jasności ...

git checkout feature-branch
git log master..HEAD

wymienia zatwierdzenia w gałęzi funkcji, ale nie w gałęzi nadrzędnej (zazwyczaj jest to główna gałąź).

Bryan
źródło
12

Może to mogłoby pomóc:

git show-branch

grzuy
źródło
2
Chociaż może to teoretycznie odpowiedzieć na pytanie, lepiej byłoby zawrzeć tutaj zasadnicze części odpowiedzi i podać link do odniesienia.
Vladimir Panteleev
To jest całkiem pomocne. Zobacz stackoverflow.com/a/7623339/874188, aby uzyskać bardziej szczegółowy przykład i kilka powiązanych odpowiedzi.
tripleee
7

Spróbuj tego:

git rev-list --all --not $(git rev-list --all ^branch)

Gruntownie git rev-list --all ^branch pobiera wszystkie wersje nie w gałęzi, a następnie wszystkie wersje w repozytorium i odejmuje poprzednią listę, która jest wersjami tylko w gałęzi.

Po komentarzach @ Briana:

Z dokumentacji git rev-list:

List commits that are reachable by following the parent links from the given commit(s)

Więc takie polecenie git rev-list A gdzie A jest zatwierdzeniem wyświetli listę zatwierdzeń, które są osiągalne z A włącznie z A.

Mając to na uwadze, coś w stylu

git rev-list --all ^A

wyświetli listę zatwierdzeń nieosiągalnych z A

Więc git rev-list --all ^branch wyświetli listę wszystkich zatwierdzeń nieosiągalnych z końca gałęzi. Który usunie wszystkie zatwierdzenia w gałęzi, lub innymi słowy, zmiany, które są tylko w innych gałęziach.

A teraz przejdźmy do git rev-list --all --not $(git rev-list --all ^branch)

To będzie jak git rev-list --all --not {commits only in other branches}

Więc chcemy wymienić all , do których nie można dotrzećall commits only in other branches

Który jest zbiorem zatwierdzeń, które są tylko w gałęzi. Weźmy prosty przykład:

             master

             |

A------------B

  \

   \

    C--------D--------E

                      |

                      branch

Tutaj celem jest uzyskanie D i E, a zatwierdzeń nie ma w żadnej innej gałęzi.

git rev-list --all ^branch dać tylko B

Teraz do git rev-list --all --not Bczego doszliśmy. Co jest również git rev-list -all ^B- chcemy, aby wszystkie zatwierdzenia nie były osiągalne z B. W naszym przypadku jest to D i E. Właśnie tego chcemy.

Mam nadzieję, że to wyjaśnia, jak polecenie działa poprawnie.

Edytuj po komentarzu:

git init
echo foo1 >> foo.txt
git add foo.txt
git commit -am "initial valid commit"
git checkout -b merge-only
echo bar >> bar.txt
git add bar.txt
git commit -am "bad commit directly on merge-only"
git checkout master
echo foo2 >> foo.txt 
git commit -am "2nd valid commit on master"

Po wykonaniu powyższych kroków, jeśli zrobisz a git rev-list --all --not $(git rev-list --all ^merge-only), otrzymasz commit, którego szukałeś - ten "bad commit directly on merge-only".

Ale gdy wykonasz ostatni krok w swoich krokach, git merge masterpolecenie nie da oczekiwanych wyników. Ponieważ na razie nie ma zatwierdzenia, którego nie ma w trybie scalania, ponieważ jedno dodatkowe zatwierdzenie w trybie głównym również zostało scalone, aby uzyskać tylko scalanie. Więc git rev-list --all ^branchdaje wynik pusty, a tym samym git rev-list -all --not $(git rev-list --all ^branch)daje wszystkie te rewizje w seryjnej tylko.

manojlds
źródło
1
Hm ... nie wiem dlaczego, ale to nie do końca działa. Potokowanie wyjścia polecenia do xargs -L 1 -t git branch -a --containspokazania wielu fałszywych alarmów (zatwierdzeń, które w rzeczywistości znajdują się w innych gałęziach). Próbowałem zi bez --no-merges. Dzięki za odpowiedź!
jimmyorr
Wydaje się, że działa dobrze dla mnie, o ile widzę w fałszywym repozytorium git.
manojlds
Dodałem kroki, aby utworzyć fałszywe repozytorium git, aby pomóc zademonstrować problem z Twoją odpowiedzią.
jimmyorr
Ach, ups. Głosowałem za tym, zanim przemyślałem to do końca. git rev-list --all ^branchda ci wszystkie zatwierdzenia, których nie ma branch. Następnie odejmujesz to od listy, która jest w branch; ale z definicji nie ma wszystkich zatwierdzeń, których nie branchma branch, więc niczego nie odejmujesz. To, czego szuka jimmyorr, to commity, które są, branchale ich nie ma master, ani żadna inna gałąź. Nie chcesz odejmować zatwierdzeń, których nie ma branch; chcesz odjąć zatwierdzenia, które są w innych gałęziach.
Brian Campbell
1
@manojlds "(wszystkie wersje) - (wszystkie wersje nie w gałęzi) = wersja w gałęzi." Tak, to działa, aby uzyskać wszystkie wersje branch, ale tak samo git rev-list branch. Po prostu piszesz git rev-list branchw bardziej skomplikowany (i wolniejszy) sposób. Nie działa odpowiedź na pytanie, jak znaleźć wszystkie zatwierdzenia branch , których nie ma w żadnej innej gałęzi .
Brian Campbell
2

Kolejna odmiana akceptowanych odpowiedzi do użycia z master

git log origin/master --not $(git branch -a | grep -Fv master)

Filtruj wszystkie zatwierdzenia, które mają miejsce w dowolnej gałęzi innej niż główna.

JaimeJorge
źródło
0

To nie jest do końca prawdziwa odpowiedź, ale potrzebuję dostępu do formatowania i dużo miejsca. Spróbuję opisać teorię stojącą za tym, co uważam za dwie najlepsze odpowiedzi: zaakceptowaną i (przynajmniej obecnie) najwyżej sklasyfikowaną . Ale w rzeczywistości odpowiadają na różne pytania .

Zatwierdzenia w Git są bardzo często „na” więcej niż jednej gałęzi naraz. Rzeczywiście, w dużej mierze o to chodzi w tym pytaniu. Dany:

...--F--G--H   <-- master
         \
          I--J   <-- develop

gdzie wielkie litery stanąć do rzeczywistych Git identyfikatorów hash, jesteśmy często szukają tylko popełnićH lub popełnia tylkoI-J w naszej git logmocy. Zatwierdzenia do góry Gznajdują się w obu gałęziach, więc chcielibyśmy je wykluczyć.

(Zwróć uwagę, że na wykresach narysowanych w ten sposób nowsze zatwierdzenia znajdują się po prawej stronie. Nazwy wybierają pojedynczy zatwierdzenie najbardziej na prawo w tej linii. Każde z tych zatwierdzeń ma zatwierdzenie nadrzędne, które jest zatwierdzeniem po ich lewej stronie: rodzicem Hjest G, a rodzicem Jjest I. Element rodzicem znowu Ijest G. Element nadrzędny Gjest Fi Fma rodzica, którego po prostu nie ma tutaj: jest częścią ...sekcji).

W tym szczególnie prostym przypadku możemy użyć:

git log master..develop    # note: two dots

do obejrzenia I-Jlub:

git log develop..master    # note: two dots

Htylko do przeglądania . Nazwa po prawej stronie, po dwóch kropkach, mówi Gitowi: tak, te zatwierdzenia . Nazwa po lewej stronie, przed dwiema kropkami, mówi Gitowi: nie, nie te zatwierdzenia . Git zaczyna się na końcu - przy zatwierdzaniu Hlub zatwierdzaniu J- i działa wstecz . Aby uzyskać (dużo) więcej informacji na ten temat, zobacz Think Like (a) Git .

Sposób sformułowania oryginalnego pytania polega na znalezieniu zatwierdzeń, które są osiągalne z jednej konkretnej nazwy, ale nie z innej nazwy w tej samej kategorii ogólnej. To znaczy, jeśli mamy bardziej złożony wykres:

               O--P   <-- name5
              /
             N   <-- name4
            /
...--F--G--H--I---M   <-- name1
         \       /
          J-----K   <-- name2
           \
            L   <-- name3

moglibyśmy wybrać jedną z tych nazw, na przykład name4lub name3, i zapytać: które zmiany można znaleźć pod tą nazwą, ale nie pod żadną inną? Jeśli wybierzemy, name3odpowiedzią jest zobowiązanie L. Jeśli wybierzemy name4, odpowiedź brzmi: w ogóle nie ma zatwierdzeń: zatwierdzenie, którego name4nazwy są zatwierdzone, Nale zatwierdzone, Nmożna znaleźć, zaczynając od name5i pracując wstecz.

Zaakceptowana odpowiedź działa z nazwami zdalnego śledzenia, a nie nazwami gałęzi, i umożliwia wyznaczenie jednej - pisanej origin/merge-only- jako wybranej nazwy i przejrzenie wszystkich innych nazw w tej przestrzeni nazw. Unika również pokazywania scaleń: jeśli wybierzemy name1jako „interesującą nazwę” i powiemy, że pokażemy mi zatwierdzenia, do których można dotrzeć, name1ale nie pod inną nazwą , zobaczymy zarówno zatwierdzenie scalające, Mjak i zwykłe I.

Najpopularniejsza odpowiedź jest zupełnie inna. Chodzi o przechodzenie przez wykres zatwierdzeń bez podążania za obydwoma etapami scalania i bez pokazywania jakichkolwiek zatwierdzeń, które scalane. Jeśli zaczniemy name1, na przykład, nie pokażemy M(jest to scalanie), ale zakładając, że pierwszym rodzicem merge Mjest commit I, nie będziemy nawet patrzeć na commits Ji K. Będziemy skończyć pokazując popełnienia I, a także zobowiązuje się H, G, F, i tak dalej, żaden z nich są commity scalania i wszystkie są osiągalne przez zaczynając Mi działa wstecz, odwiedzając tylko pierwszego rodzica każdego scalającej.

Najpopularniejsza odpowiedź jest całkiem odpowiednia, na przykład do sprawdzenia, masterkiedy masterma być gałęzią tylko do scalania. Jeśli cała "prawdziwa praca" została wykonana na gałęziach bocznych, które następnie zostały scalone master, otrzymamy następujący wzór:

I---------M---------N   <-- master
 \       / \       /
  o--o--o   o--o--o

gdzie wszystkie zatwierdzenia nienazwane na litery osą zwykłymi (nie łączonymi) zatwierdzeniami Mi Nsą zatwierdzeniami scalającymi. Commit Ijest początkowym zatwierdzeniem: pierwszym zatwierdzeniem kiedykolwiek wykonanym i jedynym, który powinien znajdować się na serwerze głównym, który nie jest zatwierdzeniem scalającym. Jeśli git log --first-parent --no-merges masterpokazuje jakikolwiek inny commit niżI , mamy taką sytuację:

I---------M----*----N   <-- master
 \       / \       /
  o--o--o   o--o--o

gdzie chcemy zobaczyć commit, *który został wykonany bezpośredniomaster , a nie przez scalenie jakiejś gałęzi funkcji.

Krótko mówiąc, popularna odpowiedź świetnie nadaje się do sprawdzania, masterkiedy masterma być przeznaczona tylko do scalania, ale nie jest tak dobra w innych sytuacjach. Zaakceptowana odpowiedź działa w innych sytuacjach.

Są nazwami zdalnego śledzenia, takimi jak origin/master oddział nazw ?

Niektóre części Gita mówią, że tak nie jest:

git checkout master
...
git status

mówi on branch master, ale:

git checkout origin/master
...
git status

mówi HEAD detached at origin/master. Wolę się zgodzić z git checkout/ git switch: origin/masternie jest nazwą oddziału ponieważ nie można się na nim „załapać”.

Zaakceptowana odpowiedź używa nazw zdalnego śledzenia origin/*jako „nazw oddziałów”:

git log --no-merges origin/merge-only \
    --not $(git for-each-ref --format="%(refname)" refs/remotes/origin |
    grep -Fv refs/remotes/origin/merge-only)

Środkowa linia, która wywołuje git for-each-ref, iteruje po nazwach zdalnego śledzenia dla nazwanego pilotaorigin .

Powodem jest to dobre rozwiązanie pierwotnego problemu jest to, że jesteśmy zainteresowani tutaj w cudze nazwiska branży, zamiast naszymi nazwiskami branży. Ale to oznacza, że ​​zdefiniowaliśmy gałąź jako coś innego niż nasze nazwy gałęzi . W porządku: po prostu bądź świadomy, że to robisz, kiedy to robisz.

git log przechodzi przez jakąś część (y) wykresu zatwierdzenia

To, czego tak naprawdę szukamy, to serie tego, co nazwałem dagletami: zobacz Co dokładnie rozumiemy przez „gałąź”? Oznacza to, że szukamy fragmentów w pewnym podzbiorze ogólnego wykresu zatwierdzeń .

Za każdym razem, gdy Git patrzy na nazwę gałęzi master, taką jak nazwa tagu v2.1lub nazwa zdalnego śledzenia, taka jak origin/master, zwykle chcemy, aby Git powiedział nam o tym zatwierdzeniu i każdym zatwierdzeniu, do którego możemy się dostać z tego zatwierdzenia: zaczynając od tego i pracując wstecz.

W matematyce nazywa się to chodzeniem po wykresie . Wykres zatwierdzenia Gita jest ukierunkowanym wykresem acyklicznym lub DAG i ten rodzaj wykresu jest szczególnie odpowiedni do chodzenia. Przechodząc po takim wykresie, odwiedzamy każdy wierzchołek wykresu, do którego można dotrzeć za pomocą używanej ścieżki. Wierzchołki na wykresie Git są zatwierdzeniami, a krawędzie są łukami - łączami jednokierunkowymi - przechodzącymi od każdego dziecka do każdego rodzica. (Tutaj Think Like (a) Git . Jednokierunkowa natura łuków oznacza, że ​​Git musi działać wstecz, od dziecka do rodzica.)

Dwa główne polecenia Gita do poruszania się po wykresie to git logi git rev-list. Te polecenia są niezwykle podobne - w rzeczywistości są w większości zbudowane z tych samych plików źródłowych - ale ich wyjście jest inne: git logtworzy dane wyjściowe do odczytania przez ludzi, podczas gdy git rev-listtworzy dane wyjściowe przeznaczone do odczytu przez inne programy Git. 1 Obie komendy wykonują ten rodzaj spaceru po wykresie.

Spacer po wykresie, który wykonują, jest konkretnie: mając pewien zestaw zatwierdzeń punktu początkowego (może tylko jeden zatwierdzenie, być może kilka identyfikatorów hash, być może kilka nazw, które rozwiązują się jako hash ID), przejdź po wykresie, odwiedzając commits . Poszczególne dyrektywy, takie jak --notlub przedrostek ^, lub --ancestry-path, lub --first-parent, w jakiś sposób modyfikują przebieg wykresu .

Przechodząc po wykresie, odwiedzają każde zatwierdzenie. Ale drukują tylko wybrany podzbiór zatwierdzeń przechodzących. Dyrektywy takie jak --no-mergeslub --before <date>informują kod chodzący po wykresie, który zobowiązuje się do wydrukowania .

Aby wykonać tę wizytę, po jednym zatwierdzeniu na raz, te dwie komendy używają kolejki priorytetowej . Uruchomić git logalbo git rev-listi nadać mu pewne Punkt startowy zobowiązuje. Umieszczają te zatwierdzenia w kolejce priorytetowej. Na przykład prosty:

git log master

zamienia nazwę masterna nieprzetworzony identyfikator skrótu i ​​umieszcza ten identyfikator w kolejce. Lub:

git log master develop

zamienia obie nazwy w hash ID i - zakładając, że są to dwa różne hash ID - umieszcza oba w kolejce.

Priorytet zatwierdzeń w tej kolejce jest określany przez jeszcze więcej argumentów. Na przykład argument --author-date-ordermówi git loglub git rev-listma używać sygnatury czasowej autora zamiast sygnatury czasowej osoby zatwierdzającej. Domyślnie używa się sygnatury czasowej osoby zatwierdzającej i wybiera zatwierdzenie według daty najnowszej: to z najwyższą datą liczbową. Tak więc master develop, zakładając, że te rozwiązania dotyczą dwóch różnych zatwierdzeń, Git pokaże, który z nich pojawił się później jako pierwszy, ponieważ będzie to na początku kolejki.

W każdym razie chodzący kod rewizji działa teraz w pętli:

  • Podczas gdy w kolejce są zatwierdzenia:
    • Usuń pierwszą pozycję kolejki.
    • Zdecyduj, czy w ogóle drukować to zatwierdzenie. Na przykład --no-merges: nie drukuj nic, jeśli jest to zatwierdzenie scalające; --before: nic nie drukuj, jeśli jego data nie przypada przed wyznaczonym czasem. Jeśli drukowanie nie jest wyłączone, wypisz zatwierdzenie: for git log, pokaż jego dziennik; dla git rev-list, wypisuje jego hash ID.
    • Umieść część lub wszystkie zmiany nadrzędne tego zatwierdzenia w kolejce (o ile go tam nie ma i nie był już odwiedzany 2 ). Normalnym ustawieniem domyślnym jest umieszczenie wszystkich rodziców. Użycie --first-parentpomija wszystkie elementy oprócz pierwszego rodzica każdego scalania.

(Oba git logi git rev-listmogą upraszczać historię z lub bez przepisywania rodzica również w tym momencie, ale pominiemy to tutaj).

W przypadku prostego łańcucha, takiego jak rozpoczynanie od HEADi praca wstecz, gdy nie ma zatwierdzeń scalających, kolejka zawsze ma jedno zatwierdzenie na początku pętli. Jest jedno zatwierdzenie, więc zdejmujemy go i drukujemy, a następnie umieszczamy jego (pojedynczego) rodzica w kolejce i ponownie jedziemy, a następnie podążamy za łańcuchem wstecz, aż dotrzemy do pierwszego zatwierdzenia, albo użytkownik zmęczy się git logwyjściem program. W tym przypadku żadna z opcji zamówienia nie ma znaczenia: zawsze jest tylko jedno zobowiązanie do wyświetlenia.

Kiedy występują połączenia i podążamy za obojgiem rodziców - obydwie „odnogi” scalania - lub gdy dajesz git loglub git rev-listwięcej niż jedno zatwierdzenie początkowe, opcje sortowania mają znaczenie.

Na koniec rozważ efekt --notlub^ przed specyfikatorem zatwierdzenia. Można je zapisać na kilka sposobów:

git log master --not develop

lub:

git log ^develop master

lub:

git log develop..master

wszystkie oznaczają to samo. To --notjest jak przedrostek^ poza tym, że odnosi się do więcej niż jednej nazwy:

git log ^branch1 ^branch2 branch3

oznacza nie gałąź1, nie gałąź2, tak gałąź3;ale:

git log --not branch1 branch2 branch3

oznacza nie gałąź1, nie gałąź2, nie gałąź3 i musisz użyć drugiej--not aby ją wyłączyć:

git log --not branch1 branch2 --not branch3

co jest trochę niezręczne. Dwie dyrektywy „nie” są połączone za pomocą XOR, więc jeśli naprawdę chcesz, możesz napisać:

git log --not branch1 branch2 ^branch3

to znaczy nie gałąź1, nie gałąź2, tak gałąź3 , jeśli chcesz zaciemnić .

Wszystko to działa poprzez wpływ na spacer po wykresie. Podczas poruszania się po wykresie git loglub git rev-listprzechodzenia przez wykres, zapewnia, że nie umieszcza w kolejce priorytetów żadnego zatwierdzenia, które jest osiągalne z któregokolwiek z zanegowanych odwołań. (W rzeczywistości wpływają one również na konfigurację początkową: zanegowane zatwierdzenia nie mogą przejść do kolejki priorytetów bezpośrednio z wiersza poleceń, więc git log master ^masterna przykład nic nie pokazuje).

Cała fantazyjna składnia opisana w dokumentacji gitrevisions wykorzystuje to i możesz to ujawnić za pomocą prostego wywołania git rev-parse. Na przykład:

$ git rev-parse origin/pu...origin/master     # note: three dots
b34789c0b0d3b137f0bb516b417bd8d75e0cb306
fc307aa3771ece59e174157510c6db6f0d4b40ec
^b34789c0b0d3b137f0bb516b417bd8d75e0cb306

Składnia z trzema kropkami oznacza zatwierdzenia dostępne z lewej lub prawej strony, ale z wyłączeniem zatwierdzeń osiągalnych z obu . W tym przypadku origin/masterzatwierdzenie b34789c0b, jest samo osiągalne z origin/pu(fc307aa37... ), więc origin/masterhash pojawia się dwukrotnie, raz z negacją, ale w rzeczywistości Git osiąga składnię z trzema kropkami, umieszczając dwie dodatnie referencje - dwa nie negowane hash ID - i jeden ujemny, reprezentowany przez ^przedrostek.

Podobnie:

$ git rev-parse master^^@
2c42fb76531f4565b5434e46102e6d85a0861738
2f0a093dd640e0dad0b261dae2427f2541b5426c

Te ^@środki składniowe wszyscy rodzice dany popełnić , a master^sama-pierwszy rodzic commit wybrany przez oddział-name master-jest scalającej, więc ma dwoje rodziców. To są dwoje rodziców. I:

$ git rev-parse master^^!
0b07eecf6ed9334f09d6624732a4af2da03e38eb
^2c42fb76531f4565b5434e46102e6d85a0861738
^2f0a093dd640e0dad0b261dae2427f2541b5426c

Te ^!środki przyrostek commit się, ale żaden z jego rodzicami . W tym przypadku master^jest 0b07eecf6.... Widzieliśmy już oboje rodziców z^@ przyrostkiem; tutaj są znowu, ale tym razem zaprzeczeni.


1 Wiele programów Git działa dosłowniegit rev-list z różnymi opcjami i czyta ich wyjście, aby wiedzieć, jakich zatwierdzeń i / lub innych obiektów Gita użyć.

2 Ponieważ wykres jest acykliczny , można zagwarantować, że żaden z nich nie został jeszcze odwiedzony, jeśli dodamy ograniczenie, nigdy nie pokazuj rodzica przed pokazaniem wszystkich jego dzieci jako priorytetu. --date-order, --author-date-orderi--topo-order dodaj to ograniczenie. Domyślna kolejność sortowania - która nie ma nazwy - nie. Jeśli znaczniki czasu zatwierdzenia są niewyraźne - na przykład niektóre zatwierdzenia zostały wykonane „w przyszłości” przez komputer, którego zegar był wyłączony - może to w niektórych przypadkach prowadzić do dziwnie wyglądających wyników.


Jeśli dotarłeś tak daleko, teraz dużo wiesz o tym git log

Podsumowanie:

  • git log polega na wyświetlaniu wybranych zatwierdzeń podczas chodzenia po części lub całości wykresu.
  • --no-mergesArgument znaleźć zarówno w zaakceptowana i aktualnie najlepszych w rankingu odpowiedzi, hamuje pokazujące jakieś rewizje, które chodził.
  • --first-parentArgument z aktualnie-top-rankingu-odpowiedź, hamuje chodzenia niektóre części wykresu, podczas wykresu-chodzić sama.
  • --notPrefiks do argumentów wiersza poleceń, jak stosowane w przyjętym odpowiedź, hamuje kiedykolwiek odwiedzić niektóre części wykresu w ogóle, od samego początku.

Korzystając z tych funkcji, otrzymujemy odpowiedzi, które lubimy, na dwa różne pytania.

torek
źródło