Git log, aby uzyskać zatwierdzenia tylko dla określonej gałęzi

214

Chcę wyświetlić listę wszystkich zatwierdzeń, które są tylko częścią określonej gałęzi.

Poniżej wymieniono wszystkie zatwierdzenia z oddziału, ale także od rodzica (master)

git log mybranch

Inną opcją, którą znalazłem, było wykluczenie zatwierdzeń osiągalnych przez mistrza i daje mi to, czego chcę, ALE chciałbym uniknąć potrzeby znajomości nazw innych gałęzi.

git log mybranch --not master

Próbowałem użyć git for-each-ref, ale zawiera on również listę mojej firmy, więc w rzeczywistości wyklucza wszystkie:

git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

Aktualizacja:

Testuję nową opcję, którą znalazłem jakiś czas temu i do tej pory wydaje się, że może to być to, czego szukałem:

git log --walk-reflogs mybranch

Aktualizacja (2013-02-13T15: 08):

Opcja --walk-reflogs jest dobra, ale sprawdziłem, czy upłynęła data ważności reflogs (domyślnie 90 dni, gc.reflogExpire ).

Myślę, że znalazłem odpowiedź, której szukałem:

git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/mybranch")

Właśnie usuwam bieżącą gałąź z listy dostępnych gałęzi i używam tej listy do wykluczenia z dziennika. W ten sposób otrzymuję tylko zatwierdzenia, które są osiągalne tylko przez mybranch .

dimirc
źródło
możliwy duplikat ze stackoverflow.com/questions/53569
StarPinkER
Widziałem już to pytanie, ale nie to samo
dimirc
2
Jesteś pewien, że tego właśnie chcesz? Uważam, że lepiej jest mieć na uwadze cel: „co jest w mojej gałęzi, która nie znajduje się w górnej części”, lub „co jest w mojej gałęzi, która nie jest w master”. Ponadto, podczas gdy git jest szybki w przycinaniu, będzie to droższe, ponieważ masz więcej gałęzi. Mam skrypt, którego używam, który nazywam „git missing” po poleceniu „brakującym” bzr. Można go znaleźć tutaj: github.com/jszakmeister/etc/blob/master/git-addons/git-missing .
John Szakmeister
1
Właściwie potrzebuję tego do haka po odbiorze, więc „master” nie zawsze będzie odgałęzieniem do wykluczenia
dimirc
Tak, duplikat wspomniany przez StarPinkER działał dla mnie dobrze: git log $ (git merge-base HEAD branch) .. oddział
charo

Odpowiedzi:

165

Z tego, co wydaje się, że powinieneś używać cherry:

git cherry -v develop mybranch

To pokazałoby wszystkie zmiany, które są zawarte w mybranch , ale NIE są w fazie rozwoju . Jeśli odrzucisz ostatnią opcję ( mybranch ), zamiast tego porówna ona obecną gałąź.

Jak zauważył VonC, ZAWSZE porównujesz swoją gałąź do innej gałęzi, więc poznaj swoje gałęzie, a następnie wybierz, którą z nich porównać.

Smilie
źródło
4
Właśnie tego potrzebowałem, ale wydaje się, że powinna istnieć bardziej intuicyjna komenda (tak, nawet w świecie Git).
Seth
12
Możesz także zrobić git cherry -v masterporównanie aktualnej gałęzi z gałęzią główną.
Pithikos
2
Niebezpieczeństwo korzystania z git cherry polega na tym, że zatwierdzenia są dopasowywane tylko wtedy, gdy ich różnice w plikach są identyczne między gałęziami. Jeśli zostanie wykonane jakiekolwiek scalenie, które różnicuje różnice między jedną gałęzią a drugą, to git cherry widzi je jako różne zatwierdzenia.
Ben
To mi tylko daje fatal: Unknown commit mybranch.
Matt Arnold
1
@MattArnold musisz zmienić tekst „develop” i „mybranch” na gałęzie istniejące na Twoim repozytorium
Smilie
40

ALE chciałbym uniknąć potrzeby znajomości nazw innych gałęzi.

Nie sądzę, aby było to możliwe: gałąź w Git jest zawsze oparta na innym lub przynajmniej innym zatwierdzeniu, jak wyjaśniono w „ git diff nie pokazuje wystarczającej ilości ”:

wprowadź opis zdjęcia tutaj

Potrzebujesz punktu odniesienia dla twojego dziennika, aby pokazać właściwe zatwierdzenia.

Jak wspomniano w „ GIT - skąd mam oddział? ”:

gałęzie są po prostu wskaźnikami do niektórych zatwierdzeń w DAG

Więc nawet jeśli git log master..mybranchjest jedna odpowiedź, nadal pokazuje zbyt wiele zmian, jeślimybranch jest oparty na myotherbranchsamym sobie master.

Aby znaleźć to odniesienie (pochodzenie twojej gałęzi), możesz tylko analizować zatwierdzenia i zobaczyć, w której gałęzi są, jak widać na:

VonC
źródło
26

W końcu znalazłem sposób na zrobienie tego, co chciał PO. To tak proste, jak:

git log --graph [branchname]

Polecenie wyświetli wszystkie zatwierdzenia, które są osiągalne z podanej gałęzi w formacie wykresu. Ale możesz łatwo filtrować wszystkie zatwierdzenia w tej gałęzi, patrząc na wykres zatwierdzeń, który *jest pierwszym znakiem w linii zatwierdzeń.

Na przykład spójrzmy na fragment git log --graph masterrepozytorium GitHub cakephp poniżej:

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <[email protected]>
| | Date:   Tue Aug 30 08:01:59 2016 +0200
| |
| |     Merge pull request #9367 from cakephp/fewer-allocations
| |
| |     Do fewer allocations for simple default values.
| |
| * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
| | Author: Mark Story <[email protected]>
| | Date:   Mon Aug 29 22:21:16 2016 -0400
| |
| |     The action should only be defaulted when there are no patterns
| |
| |     Only default the action name when there is no default & no pattern
| |     defined.
| |
| * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
| | Author: Mark Story <[email protected]>
| | Date:   Sun Aug 28 22:35:20 2016 -0400
| |
| |     Do fewer allocations for simple default values.
| |
| |     Don't allocate arrays when we are only assigning a single array key
| |     value.
| |
* |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
|\ \  Merge: 10e5734 43178fd
| |/  Author: Mark Story <[email protected]>
|/|   Date:   Mon Aug 29 22:15:30 2016 -0400
| |
| |       Merge pull request #9322 from cakephp/add-email-assertions
| |
| |       Add email assertions trait
| |
| * commit 43178fd55d7ef9a42706279fa275bb783063cf34
| | Author: Jad Bitar <[email protected]>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

Jak widać, tylko rewizje 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4i c3f45e811e4b49fe27624b57c3eb8f4721a4323bmają *jako pierwszy znak w linii popełnić. Te zatwierdzenia pochodzą z gałęzi głównej, a pozostałe cztery z innych gałęzi.

Lukman
źródło
11

Następujące polecenie powłoki powinno robić, co chcesz:

git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)

Ostrzeżenia

Jeśli mybranchwymeldowałeś się, powyższe polecenie nie będzie działać. To dlatego, że zatwierdzenia mybranchsą również osiągalne przez HEAD, więc Git nie uważa, że ​​zatwierdzenia są unikalne dla mybranch. Aby działał, gdy mybranchjest wyrejestrowany, musisz również dodać wykluczenie dla HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD \
    --all)

Nie należy jednak wykluczać, HEADchyba żemybranch jest zaznaczone, w przeciwnym razie ryzykujesz pokazanie zatwierdzeń, które nie są wyłączne mybranch.

Podobnie, jeśli masz zdalny oddział o nazwie origin/mybranchodpowiadający mybranchoddziałowi lokalnemu , musisz go wykluczyć:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --all)

A jeśli gałąź zdalna jest domyślną gałęzią dla zdalnego repozytorium (zwykle tylko dla origin/master), musisz również wykluczyć origin/HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Jeśli masz wyewidencjonowany oddział, i istnieje gałąź zdalna, a gałąź zdalna jest domyślna dla zdalnego repozytorium, to w rezultacie wykluczasz wiele:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Wyjaśnienie

The git rev-list komenda jest komendą niskopoziomową (hydrauliczną), która przeprowadza daną wersję i zrzuca napotkane identyfikatory SHA1. Pomyśl o tym jako równoważnym, git logz tym wyjątkiem, że pokazuje tylko SHA1 - brak wiadomości w dzienniku, bez nazwiska autora, bez znacznika czasu, żadnych z tych „wymyślnych” rzeczy.

Ta --no-walkopcja, jak sama nazwa wskazuje, uniemożliwia git rev-listchodzenie po łańcuchu przodków. Więc jeśli napiszeszgit rev-list --no-walk mybranch , wydrukuje tylko jeden identyfikator SHA1: identyfikator zatwierdzenia końcówkimybranch oddziału.

Te --exclude=refs/heads/mybranch --allargumenty powiedziećgit rev-list zacząć od każdego odwołania z wyjątkiemrefs/heads/mybranch .

Tak więc, kiedy uruchomisz git rev-list --no-walk --exclude=refs/heads/mybranch --all, Git drukuje identyfikator SHA1 zatwierdzenia tip dla każdego ref z wyjątkiem refs/heads/mybranch. Te zobowiązania i ich przodkowie są zobowiązaniami, którymi nie jesteś zainteresowany - są to zobowiązania, które robisz nie interesujesz chcesz widzieć.

W innych commity są te, które chcesz zobaczyć, więc zbierać wyjściegit rev-list --no-walk --exclude=refs/heads/mybranch --all i powiedzieć Git, aby zobaczyć wszystko, ale te rewizje i ich przodków.

The --no-walkArgumentem jest to konieczne dla dużych repozytoriów (i jest optymalizacja dla małych repozytoriach): Bez niej, Git będzie musiał wydrukować, a powłoka musiałby zbierać (i przechowywać w pamięci) wiele więcej popełnić identyfikatory niż to konieczne. Przy dużym repozytorium liczba zebranych zatwierdzeń może łatwo przekroczyć limit argumentów powłoki w wierszu poleceń.

Masz błąd?

Spodziewałbym się, że zadziała:

git log --all --not --exclude=refs/heads/mybranch --all

ale tak nie jest. Zgaduję, że to błąd w Git, ale może to celowe.

Richard Hansen
źródło
Ładne wyjaśnienie. +1
VonC
5
Przybyłem tutaj, żeby wiedzieć, jak robić Mercurial hg log -b <branch>. Nie rozumiem, dlaczego ludzie mówią, że git jest nieprzyjazny. / s
weberc2
Nie wiem, dlaczego git log --all --not --exclude=refs/heads/mybranch --allnie działa, ale git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --alldziała, z tymi samymi zastrzeżeniami dotyczącymi wykluczenia HEAD i pochodzenia.
Ben C
8

Szybka odpowiedź:

git log $(git merge-base master b2)..HEAD

Powiedzmy:

  1. Że masz gałąź główną

  2. Zrób kilka zobowiązań

  3. Utworzyłeś oddział o nazwie b2

  4. Czy git log -n1; identyfikator zatwierdzenia jest bazą scalającą między b2 a master

  5. Wykonaj kilka zmian w b2

  6. git log pokaże twoją historię logów b2 i master

  7. Użyj zakresu zatwierdzania, jeśli nie znasz pojęcia, zapraszam do google lub stosu przepełnienia,

    W twoim rzeczywistym kontekście możesz to zrobić na przykład

    git log commitID_FOO..comitID_BAR
    

    „..” to operator zakresu dla komendy log.

    To znaczy, w prostej formie, daj mi wszystkie logi nowsze niż commitID_FOO ...

  8. Spójrz na punkt # 4, bazę scalania

    Więc: git log COMMITID_mergeBASE..HEADpokaże różnicę

  9. Git może pobrać bazę scalania w ten sposób

    git merge-base b2 master
    
  10. Wreszcie możesz zrobić:

    git log $(git merge-base master b2)..HEAD
    
Frederic Nault
źródło
4

Możesz spróbować czegoś takiego:

#!/bin/bash

all_but()
{
    target="$(git rev-parse $1)"
    echo "$target --not"
    git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
    while read entry
    do
        eval "$entry"

        test "$ref" != "$target" && echo "$ref"
    done
}

git log $(all_but $1)

Lub, pożyczając z przepisu w Podręczniku użytkownika Git :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )
John Szakmeister
źródło
+1. W mojej odpowiedzi pisałem, że trzeba przeanalizować zatwierdzenia, aby znaleźć pochodzenie oddziału, i wydaje się, że właśnie to zrobiłeś.
VCC
Czy używałeś dziennika --walk-reflogs? Czytam o tej opcji i daje mi wyniki, których potrzebuję do tej pory (wciąż
testuję
@dimirc Reflogi są razem inną bestią. Rejestruje punkty rozgałęzień w czasie, ogólnie w celu odzyskania. Nie jestem pewien, co robisz w haczyku po otrzymaniu, ale może jeśli to wyjaśnisz, ludzie mogą podać bardziej rozsądną odpowiedź na Twój problem.
John Szakmeister
Muszę tylko parsować / sprawdzać wszystkie komunikaty zatwierdzania jednym naciśnięciem. Przypadek, który chcę omówić, to sytuacja, w której ktoś wypycha wiele zatwierdzeń na master i tworzy również nową gałąź z wieloma zatwierdzeniami. Hak po odbiorze musi sprawdzić zmiany dokonane zarówno dla referencji / gałęzi, na przykład master i newbranch, muszę znać granice dla nowej gałęzi, aby uniknąć dwukrotnego analizowania komunikatów zatwierdzenia, ponieważ można je zatwierdzić z mastera.
dimirc
1
W porządku. Więc myślę, że powyższe podejście, które nakreśliłem, naprawdę jest tym, czego chcesz. Dzięki reflogowi wpisy po pewnym czasie odpadną i myślę, że spowoduje to pewne bóle głowy. Możesz też chcieć spojrzeć na używanie git show-ref --tags.
John Szakmeister
4
git rev-list --exclude=master --branches --no-walk

wyświetli wskazówki dla każdej gałęzi, która nie jest master.

git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)

wyświetli listę wszystkich zatwierdzeń w masterhistorii, których nie ma w historii żadnej innej gałęzi.

Sekwencjonowanie jest ważne dla opcji, które konfigurują potok filtrów do wyboru zatwierdzania, więc --branchesmusi przestrzegać wszelkich wzorców wykluczeń, które powinien zastosować, i --no-walkmusi podążać za filtrami dostarczającymi zatwierdzenia, lista rewizji nie powinna chodzić.

jthill
źródło
4

Spowoduje to wyświetlenie zatwierdzeń w bieżącym oddziale. Jeśli jakikolwiek argument zostanie przekazany, to po prostu wyświetla skróty.

git_show_all_commits_only_on_this_branch

#!/bin/bash
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF
  
  usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}
  
  Compares 2 different branches, and lists the commits found only 
  in the first branch (newest branch). 

  e.g. 
  
  $ME         -> default. compares current branch to master
  $ME B1      -> compares branch B1 to master
  $ME B1 B2   -> compares branch B1 to B2
  $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages
  
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show commit msgs if any arg passed for arg 3
if [ "$3" ]
then
  OPT="-v"
fi

# get branch names
OLDER_BRANCH=${2:-"master"}
if [ -z "$1" ]
then
  NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
  NEWER_BRANCH=$1
fi

if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
then
  echo "  Please supply 2 different branches to compare!"
  show_help
fi

OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)

if [ -z "$OUT" ]
then
  echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
  exit;
fi

if [ "$OPT" == "-v" ]
then
  echo "$OUT"
else
  echo "$OUT" | awk '{print $2}'
fi
Brad Parks
źródło
1
To dało mi około 100 nieistotnych komunikatów w dzienniku.
Arlie Stephens
Hej @ArlieStephens - próbowałem i wydawało się, że nadal działa dla mnie? Właśnie dodałem pomoc i więcej komunikatów o błędach do powyższego. Daj mi znać jak idzie!
Brad Parks
Ciekawy. Patrząc na kod, jaki masz teraz, myślę, że może być tak prosty, jak oryginał, zakładając, że gałąź, na której mi zależy, wyszła z mistrza. Przy obecnym kodzie mógłbym wyraźnie określić gałąź nadrzędną. (IIRC, moja gałąź deweloperów pochodzi z gałęzi wydania, a nie mistrza.)
Arlie Stephens
@ArlieStephens - tak, nie sądzę, żebym zmienił jakąkolwiek funkcjonalność .... zaktualizowałem ją jeszcze raz i uczyniłem dokumentację nieco dokładniejszą po kilku lokalnych testach ... i dodałem opcję „szczegółową”, która była tam wcześniej, ale nie udokumentowałem tego
Brad Parks
3

Używam następujących poleceń:

git shortlog --no-merges --graph --abbrev-commit master..<mybranch>

lub

git log --no-merges --graph --oneline --decorate master..<mybranch>
Alex
źródło
1

Uznałem to podejście za stosunkowo łatwe.

Kasa do oddziału i niż

  1. Biegać

    git rev-list --simplify-by-decoration -2 HEAD
    

Zapewni to tylko dwa SHA:

1) ostatnie zatwierdzenie oddziału [C1]

2) i zatwierdzić rodzica do pierwszego zatwierdzenia oddziału [C2]

  1. Teraz biegnij

    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
    

Tutaj C1 i C2 to dwa ciągi znaków, które otrzymasz po uruchomieniu pierwszego polecenia. Wpisz te wartości bez <> w drugim poleceniu.

To da listę historii zmian plików w oddziale.

Mustkeem K
źródło
Jeśli przeczytasz pierwsze trzy wiersze pytania, zobaczysz, że autor wypisuje dokładnie to polecenie i wyjaśnia, dlaczego nie jest to, czego szukają
black_fm
Ah @black_fm Wprowadziłem kilka zmian w odpowiedzi. Możesz zagłosować, jeśli okaże się to teraz przydatne. :)
Mustkeem K
0

W mojej sytuacji korzystamy z Git Flow i GitHub. Wszystko, co musisz zrobić, to: Porównaj gałąź funkcji z gałęzią programowania w GitHub.

Pokaże zatwierdzenia dokonane tylko w gałęzi funkcji.

Na przykład:

https://github.com/your_repo/compare/develop...feature_branch_name

peterpengnz
źródło
Zgadzam się, że gdy wejdziesz w sytuację „Chcę zobaczyć, jak będzie wyglądać żądanie ściągnięcia”, najlepszym rozwiązaniem jest często zignorowanie giti zamiast tego użyć GitHub, aby po prostu wysłać żądanie ściągnięcia lub porównać gałęzie.
pkamb