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 są 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 są 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.
git log ^branch1 ^branch2 merge-only-branchskładni?