Accedi a log per ottenere commit solo per un ramo specifico


214

Voglio elencare tutti i commit che fanno solo parte di un ramo specifico.

Con quanto segue, elenca tutti i commit dal ramo, ma anche dal genitore (master)

git log mybranch

L'altra opzione che ho trovato è stata quella di escludere gli commit raggiungibili dal master e mi dà quello che voglio, MA vorrei evitare la necessità di conoscere i nomi degli altri rami.

git log mybranch --not master

Stavo cercando di utilizzare git for-each-ref, ma elenca anche mybranch, quindi in realtà esclude tutto:

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

Aggiornare:

Sto testando una nuova opzione che ho trovato qualche tempo fa e fino ad ora sembra che questo potrebbe essere quello che stavo cercando:

git log --walk-reflogs mybranch

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

L'opzione --walk-reflogs è buona, ma ho verificato che ci sia una scadenza per i reflog (default 90 giorni, gc.reflogExpire ).

Penso di aver trovato la risposta che cercavo:

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

Sto solo rimuovendo il ramo corrente dall'elenco dei rami disponibili e sto usando quell'elenco per essere escluso dal registro. In questo modo ottengo solo i commit che vengono raggiunti solo da Mybranch .



Ho

2
Sei sicuro che sia quello che vuoi? Trovo migliore avere un obiettivo in mente: "cosa c'è nel mio ramo che non è a monte", o "cosa c'è nel mio ramo che non è nel maestro". Inoltre, mentre git è veloce nella potatura, questo diventerà più costoso poiché hai più rami. Ho uno script che uso che chiamo "git missing" dopo il comando "missing" di bzr. Puoi trovarlo qui: github.com/jszakmeister/etc/blob/master/git-addons/git-missing .
John Szakmeister,

1
In realtà ho bisogno di questo per un hook post-ricezione, quindi "master" non sarà sempre il ramo da escludere
dimirc

Sì, il duplicato citato da StarPinkER ha funzionato bene per me: git log $ (git merge-base HEAD branch) .. branch
charo

Risposte:


165

Da quello che sembra che dovresti usare cherry:

git cherry -v develop mybranch

Ciò mostrerebbe tutti i commit contenuti in mybranch , ma NON in fase di sviluppo . Se si interrompe l'ultima opzione ( mybranch ), verrà invece confrontato il ramo corrente.

Come ha sottolineato VonC, stai SEMPRE confrontando il tuo ramo con un altro ramo, quindi conosci i tuoi rami e quindi scegli quale confrontare.


4
Questo è esattamente ciò di cui avevo bisogno, ma sembra che ci dovrebbe essere un comando più intuitivo (sì, anche nel mondo di Git) per questo.
Seth,

12
Puoi anche fare git cherry -v masterper confrontare il tuo ramo corrente con il ramo principale.
Pithikos,

2
Il pericolo nell'uso di git cherry è che i commit sono abbinati solo se le differenze dei loro file sono identiche tra i rami. Se è stato fatto un qualsiasi tipo di fusione che renderebbe le differenze diverse tra un ramo e l'altro, allora git cherry li vede come diversi commit.
Ben

Questo mi da solo fatal: Unknown commit mybranch.
Matt Arnold,

1
@MattArnold devi cambiare il testo "sviluppo" e "mybranch" in rami esistenti nel tuo repository
Smilie,

40

MA vorrei evitare la necessità di conoscere i nomi degli altri rami.

Non credo sia possibile: un ramo in Git si basa sempre su un altro o almeno su un altro commit, come spiegato in " git diff non mostra abbastanza ":

inserisci qui la descrizione dell'immagine

È necessario un punto di riferimento per il registro per mostrare i giusti commit.

Come menzionato in " GIT - Da dove mi sono ramificato? ":

i rami sono semplicemente dei puntatori a determinati commit in un DAG

Quindi, anche se git log master..mybranchè una risposta, mostrerebbe comunque troppi commit, se mybranchbasato su myotherbranch, stesso basato su master.

Per trovare quel riferimento (l'origine del tuo ramo), puoi solo analizzare i commit e vedere in quale ramo sono, come si vede in:


26

Alla fine ho trovato il modo di fare ciò che voleva l'OP. È semplice come:

git log --graph [branchname]

Il comando visualizzerà tutti i commit raggiungibili dal ramo fornito nel formato del grafico. Tuttavia, puoi facilmente filtrare tutti i commit su quel ramo osservando il grafico dei commit il cui *primo carattere nella riga di commit.

Ad esempio, diamo un'occhiata al seguente estratto git log --graph mastersul repository GitHub di cakephp:

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <lorenzo@users.noreply.github.com>
| | 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 <mark@mark-story.com>
| | 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 <mark@mark-story.com>
| | 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 <mark@mark-story.com>
|/|   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 <jadbitar@mac.com>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

Come puoi vedere, si impegna solo 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4e c3f45e811e4b49fe27624b57c3eb8f4721a4323bha l' *essere il primo personaggio nelle righe di commit. Tali commit provengono dal ramo principale mentre gli altri quattro provengono da alcuni altri rami.


11

Il seguente comando shell dovrebbe fare quello che vuoi:

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

Avvertenze

Se hai mybranchverificato, il comando sopra non funzionerà. Questo perché anche i commit mybranchsono raggiungibili HEAD, quindi Git non considera i commit unici mybranch. Per farlo funzionare quando mybranchè stato estratto, è inoltre necessario aggiungere un'esclusione per HEAD:

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

Tuttavia, si dovrebbe non escludere HEADa meno che il mybranchè stato estratto, altrimenti si rischia di mostrare commit che non sono esclusiva mybranch.

Allo stesso modo, se si dispone di un ramo remoto denominato origin/mybranchche corrisponde al mybranchramo locale , è necessario escluderlo:

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

E se il ramo remoto è il ramo predefinito per il repository remoto (di solito è vero solo per origin/master), dovrai anche escludere 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)

Se il ramo è stato estratto e c'è un ramo remoto e il ramo remoto è l'impostazione predefinita per il repository remoto, si finisce per escludere molto:

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)

Spiegazione

Il git rev-listcomando è un comando di basso livello (idraulico) che accompagna le revisioni date e scarica gli identificatori SHA1 riscontrati. Pensalo equivalente a git logtranne che mostra solo SHA1: nessun messaggio di registro, nessun nome di autore, nessun timestamp, nessuna di quelle cose "fantasiose".

L' --no-walkopzione, come suggerisce il nome, impedisce git rev-listdi camminare sulla catena degli antenati. Quindi, se digiti git rev-list --no-walk mybranch, stamperà solo un identificatore SHA1: l'identificatore del commit tip del mybranchramo.

Gli --exclude=refs/heads/mybranch --allargomenti dicono git rev-listdi iniziare da ogni riferimento tranne che per refs/heads/mybranch.

Quindi, quando corri git rev-list --no-walk --exclude=refs/heads/mybranch --all, Git stampa l'identificatore SHA1 del commit tip di ogni ref tranne per refs/heads/mybranch. Questi commit e i loro antenati sono i commit che non ti interessano, questi sono i commit che non vuoi vedere.

Gli altri commit sono quelli che vuoi vedere, quindi raccogliamo l'output di git rev-list --no-walk --exclude=refs/heads/mybranch --alle diciamo a Git di mostrare tutto tranne quei commit e i loro antenati.

L' --no-walkargomento è necessario per i repository di grandi dimensioni (ed è un'ottimizzazione per i repository di piccole dimensioni): senza di essa, Git dovrebbe stampare e la shell dovrebbe raccogliere (e archiviare in memoria) molti più identificatori di commit del necessario. Con un repository di grandi dimensioni, il numero di commit raccolti potrebbe facilmente superare il limite dell'argomento della riga di comando della shell.

Bug bug?

Mi sarei aspettato che funzionasse:

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

ma non lo fa. Immagino che questo sia un bug in Git, ma forse è intenzionale.


Bella spiegazione. +1
VonC,

5
Sono venuto qui per sapere come fare Mercurial hg log -b <branch>. Non capisco perché la gente dice che Git sia ostile. / s
weberc2

Non so perché git log --all --not --exclude=refs/heads/mybranch --allnon funziona ma git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --allfunziona, con le stesse avvertenze sull'esclusione di HEAD e origine.
Ben C,

8

Risposta veloce:

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

Diciamo:

  1. Che hai un ramo principale

  2. Fai qualche commit

  3. Hai creato un ramo chiamato b2

  4. Fare git log -n1; l'id commit è la base di unione tra b2 e master

  5. Effettua alcuni commit in b2

  6. git log mostrerà la cronologia di log di b2 e master

  7. Utilizza l'intervallo di commit, se non hai familiarità con il concetto, ti invito a cercarlo su Google o a sovrapporlo,

    Per il tuo contesto reale, puoi fare ad esempio

    git log commitID_FOO..comitID_BAR
    

    ".." è l'operatore di intervallo per il comando di registro.

    Ciò significa che, in una forma semplice, dammi tutti i registri più recenti di commitID_FOO ...

  8. Guarda il punto 4, la base di unione

    Quindi: git log COMMITID_mergeBASE..HEADti mostrerà la differenza

  9. Git può recuperare la base di unione per te in questo modo

    git merge-base b2 master
    
  10. Finalmente puoi fare:

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

4

Potresti provare qualcosa del genere:

#!/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)

Oppure, prendendo in prestito dalla ricetta nel Manuale dell'utente di Git :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )

+1. Stavo scrivendo nella mia risposta che devi analizzare i commit per trovare l'origine del tuo ramo e sembra che tu abbia fatto proprio questo.
VonC,

Hai usato log --walk-reflogs? Sto leggendo questa opzione e mi sta dando i risultati di cui ho bisogno fino ad ora, (ancora testando)
dimirc,

I reflog di @dimirc sono una bestia diversa tutti insieme. Registra i punti di diramazione nel tempo, generalmente a scopo di recupero. Non sono sicuro di quello che stai facendo nel tuo hook post-ricezione, ma forse se lo spiegassi, la gente potrebbe fornire una risposta più sensata al tuo problema.
John Szakmeister,

Devo solo analizzare / controllare tutti i messaggi di commit con una semplice pressione. Il caso che voglio trattare è se qualcuno spinge più commit al master e crea anche una nuova filiale con più commit. L'hook post-ricezione deve verificare le modifiche apportate per entrambi i ref / rami, ad esempio master e newbranch, ho bisogno di conoscere i limiti per il nuovo ramo per evitare di analizzare due volte i messaggi di commit, poiché potrebbe essere eseguito il commit dal master.
dimirc,

1
Va bene. Quindi penso che l'approccio sopra che ho delineato sia davvero quello che vuoi. Con reflog, le voci cadranno dopo un certo periodo di tempo e penso che questo ti causerà qualche mal di testa. Potresti voler esaminare git show-ref --tagsanche l' uso .
John Szakmeister,

4
git rev-list --exclude=master --branches --no-walk

elencherà i suggerimenti di ogni ramo che non lo è master.

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

elencherà ogni commit nella mastercronologia che non è nella storia di nessun altro ramo.

Il sequenziamento è importante per le opzioni che impostano la pipeline di filtri per la selezione del commit, quindi --branchesdeve seguire tutti i modelli di esclusione che dovrebbe applicare e --no-walkdeve seguire i filtri che forniscono commit rev-list non dovrebbe camminare.


4

Questo produrrà i commit sul ramo corrente. Se viene passato un argomento, genera solo gli hash.

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

1
Ciò ha prodotto circa 100 messaggi di registro irrilevanti per me.
Arlie Stephens,

Ehi @ArlieStephens - L'ho provato e sembrava funzionare ancora per me? Ho appena aggiunto aiuto e altri messaggi di errore a quanto sopra. Fammi sapere come va!
Brad Parks,

Interessante. Guardando il codice come lo hai ora, penso che potrebbe essere semplice come l'originale, supponendo che il ramo a cui tengo sia venuto fuori dal master. Con il codice attuale, avrei potuto specificare esplicitamente il ramo padre. (IIRC, il mio ramo di sviluppo proveniva da un ramo di rilascio, non da maestro.)
Arlie Stephens,

@ArlieStephens - sì, non credo di aver cambiato alcuna funzionalità .... L'ho aggiornato ancora una volta e ho reso i documenti un po 'più esatti dopo alcuni test locali ... e ho aggiunto un'opzione "dettagliata" che era lì prima, ma non l'ho documentato
Brad Parks

3

Sto usando i seguenti comandi:

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

o

git log --no-merges --graph --oneline --decorate master..<mybranch>

1

Ho trovato questo approccio relativamente semplice.

Vai alla filiale e poi

  1. Correre

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

Ciò fornirà solo due SHA:

1) ultimo commit della filiale [C1]

2) e affidare il genitore al primo commit del ramo [C2]

  1. Adesso corri

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

Qui C1 e C2 sono due stringhe che otterrai quando esegui il primo comando. Inserisci questi valori senza <> nel secondo comando.

Ciò fornirà un elenco di cronologia della modifica dei file all'interno del ramo.


Se leggi le prime tre righe della domanda, vedrai che l'autore elenca questo comando esatto e spiega perché non è quello che stanno cercando
black_fm

Ah @black_fm Ho apportato alcune modifiche in risposta. Puoi votarlo se lo ritieni utile ora. :)
Mustkeem K,

0

Nella mia situazione, stiamo usando Git Flow e GitHub. Tutto ciò che devi fare è: confrontare il tuo ramo delle caratteristiche con il tuo ramo di sviluppo su GitHub.

Mostrerà i commit effettuati solo nel ramo della funzione.

Per esempio:

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


Sono d'accordo che quando entri nella situazione "Voglio vedere come apparirà una richiesta pull", la soluzione migliore è spesso ignorare gite invece usare GitHub per fare semplicemente una richiesta pull o confrontare i rami.
pkamb,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.