Git-Protokoll, um Commits nur für einen bestimmten Zweig zu erhalten

214

Ich möchte alle Commits auflisten, die nur Teil eines bestimmten Zweigs sind.

Im Folgenden werden alle Commits aus dem Zweig, aber auch aus dem übergeordneten (Master) aufgelistet.

git log mybranch

Die andere Option, die ich gefunden habe, war, die vom Master erreichbaren Commits auszuschließen und mir zu geben, was ich will, ABER ich möchte vermeiden, dass ich die Namen der anderen Zweige kennen muss.

git log mybranch --not master

Ich habe versucht, es zu verwenden git for-each-ref, aber es listet auch mybranch auf, so dass es eigentlich alle ausschließt:

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

Aktualisieren:

Ich teste eine neue Option, die ich vor einiger Zeit gefunden habe, und bis jetzt scheint es, dass dies das sein könnte, wonach ich gesucht habe:

git log --walk-reflogs mybranch

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

Die Option --walk-reflogs ist gut, aber ich habe überprüft, ob ein Ablauf für Reflogs vorliegt (Standard 90 Tage, gc.reflogExpire ).

Ich glaube, ich habe die Antwort gefunden, nach der ich gesucht habe:

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

Ich entferne nur den aktuellen Zweig aus der Liste der verfügbaren Zweige und verwende diese Liste, um aus dem Protokoll ausgeschlossen zu werden. Auf diese Weise erhalte ich nur die Commits, die nur von mybranch erreicht werden .

dimirc
quelle
Mögliches Duplikat mit stackoverflow.com/questions/53569
StarPinkER
Ich
2
Bist du sicher, dass du das willst? Ich finde es besser, ein Ziel im Auge zu haben: "Was ist in meinem Zweig, das nicht im Upstream ist" oder "Was ist in meinem Zweig, das nicht im Master ist". Während Git schnell beschneidet, wird dies teurer, da Sie mehr Zweige haben. Ich habe ein Skript, das ich benutze und das ich nach dem Befehl "fehlt" von bzr "git fehlt" nenne. Sie finden es hier: github.com/jszakmeister/etc/blob/master/git-addons/git-missing .
John Szakmeister
1
Ich brauche dies tatsächlich für einen Post-Receive-Hook, also wird "Master" nicht immer der Zweig sein, der ausgeschlossen werden muss
dimirc
Ja, das von StarPinkER erwähnte Duplikat hat bei mir gut funktioniert: git log $ (git merge-base HEAD-Zweig) .. branch
charo

Antworten:

165

Wie es sich anhört, sollten Sie Folgendes verwenden cherry:

git cherry -v develop mybranch

Dies würde alle Commits anzeigen , die in mybranch enthalten sind , aber NICHT in Entwicklung sind . Wenn Sie die letzte Option ( mybranch ) weglassen , wird stattdessen der aktuelle Zweig verglichen.

Wie VonC betonte, vergleichen Sie Ihre Niederlassung IMMER mit einer anderen Niederlassung. Kennen Sie also Ihre Niederlassungen und wählen Sie dann die Niederlassung aus, mit der Sie vergleichen möchten.

Smilie
quelle
4
Dies ist genau das, was ich brauchte, aber es scheint, dass es dafür einen intuitiveren Befehl geben sollte (ja sogar in der Welt von Git).
Seth
12
Sie können auch git cherry -v masterIhren aktuellen Zweig mit dem Hauptzweig vergleichen.
Pithikos
2
Die Gefahr bei der Verwendung von Git Cherry besteht darin, dass Commits nur dann abgeglichen werden, wenn ihre Dateiunterschiede zwischen den Zweigen identisch sind. Wenn irgendeine Art von Zusammenführung durchgeführt wurde, die die Unterschiede zwischen einem Zweig und dem anderen unterscheiden würde, dann sieht Git Cherry sie als unterschiedliche Commits an.
Ben
Das gibt mir nur fatal: Unknown commit mybranch.
Matt Arnold
1
@ MattArnold Sie müssen den Text "entwickeln" und "mybranch" in Zweige ändern, die auf Ihrem Repo existieren
Smilie
40

ABER ich möchte vermeiden, dass die Namen der anderen Zweige bekannt sein müssen.

Ich denke nicht, dass dies möglich ist: Ein Zweig in Git basiert immer auf einem anderen oder zumindest auf einem anderen Commit, wie in " Git Diff zeigt nicht genug " erläutert :

Geben Sie hier die Bildbeschreibung ein

Sie benötigen einen Referenzpunkt für Ihr Protokoll, um die richtigen Commits anzuzeigen.

Wie in " GIT - Woher habe ich verzweigt? " Erwähnt :

Zweige sind lediglich Zeiger auf bestimmte Commits in einer DAG

Selbst wenn git log master..mybranches sich um eine Antwort handelt, werden immer noch zu viele Commits angezeigt, wenn sie mybranchauf myotherbranchselbst basieren master.

Um diese Referenz (den Ursprung Ihres Zweigs) zu finden, können Sie nur Commits analysieren und sehen, in welchem ​​Zweig sie sich befinden, wie in:

VonC
quelle
26

Ich habe endlich den Weg gefunden, das zu tun, was das OP wollte. Es ist so einfach wie:

git log --graph [branchname]

Der Befehl zeigt alle Commits, die über den bereitgestellten Zweig erreichbar sind, im Diagrammformat an. Sie können jedoch problemlos alle Commits in diesem Zweig filtern, indem Sie *sich das Commit- Diagramm ansehen, dessen erstes Zeichen in der Commit-Zeile steht.

Schauen wir uns zum Beispiel den folgenden Auszug aus dem git log --graph masterpieHp-GitHub-Repo an:

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
| |

Wie Sie nur Commits sehen können 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4und c3f45e811e4b49fe27624b57c3eb8f4721a4323bdas haben *ist das erste Zeichen in den Linien zu begehen. Diese Commits stammen aus dem Hauptzweig, während die anderen vier aus einigen anderen Zweigen stammen.

Lukman
quelle
11

Der folgende Shell-Befehl sollte das tun, was Sie wollen:

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

Vorsichtsmaßnahmen

Wenn Sie mybranchausgecheckt haben, funktioniert der obige Befehl nicht. Das liegt daran, dass die Commits mybranchauch für erreichbar sind HEAD, sodass Git die Commits nicht als eindeutig betrachtet mybranch. Damit es beim mybranchAuschecken funktioniert , müssen Sie auch einen Ausschluss hinzufügen für HEAD:

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

Sie sollten jedoch nicht ausschließen, es HEADsei denn, das mybranchist ausgecheckt, da Sie sonst das Risiko eingehen, Commits anzuzeigen, die nicht exklusiv für sind mybranch.

Wenn Sie einen Remote-Zweig mit dem Namen haben origin/mybranch, der dem lokalen mybranchZweig entspricht, müssen Sie ihn ebenfalls ausschließen:

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

Und wenn der Remote-Zweig der Standardzweig für das Remote-Repository ist (normalerweise nur für origin/master), müssen Sie auch Folgendes ausschließen 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)

Wenn Sie den Zweig ausgecheckt haben und es einen Remote-Zweig gibt und der Remote-Zweig der Standard für das Remote-Repository ist, schließen Sie am Ende eine Menge aus:

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)

Erläuterung

Der git rev-listBefehl ist ein Befehl auf niedriger Ebene (Sanitär), der die angegebenen Revisionen durchläuft und die gefundenen SHA1-Kennungen ausgibt. Betrachten Sie es als äquivalent zu, git logaußer dass nur der SHA1 angezeigt wird - keine Protokollnachricht, kein Autorenname, kein Zeitstempel, nichts von diesem "ausgefallenen" Zeug.

Die --no-walkOption verhindert, wie der Name schon sagt, das git rev-listGehen über die Ahnenkette. Wenn Sie also eingeben git rev-list --no-walk mybranch, wird nur eine SHA1-Kennung ausgegeben: die Kennung des Tip-Commits des mybranchZweigs.

Die --exclude=refs/heads/mybranch --allArgumente sagen git rev-list, dass mit Ausnahme von jeder Referenz begonnen werden soll refs/heads/mybranch.

Wenn Sie also ausführen git rev-list --no-walk --exclude=refs/heads/mybranch --all, druckt Git die SHA1-Kennung des Tip-Commits jeder Referenz mit Ausnahme von refs/heads/mybranch. Diese Commits und ihre Vorfahren sind die Commits, an denen Sie nicht interessiert sind - dies sind die Commits, die Sie nicht sehen möchten.

Die anderen Commits sind diejenigen, die Sie sehen möchten. Daher sammeln wir die Ausgabe von git rev-list --no-walk --exclude=refs/heads/mybranch --allund weisen Git an, alles außer diesen Commits und ihren Vorfahren anzuzeigen.

Das --no-walkArgument ist für große Repositorys erforderlich (und ist eine Optimierung für kleine Repositorys): Ohne es müsste Git drucken und die Shell müsste viel mehr Festschreibungskennungen als erforderlich sammeln (und im Speicher speichern). Bei einem großen Repository kann die Anzahl der gesammelten Commits die Befehlszeilenargumentgrenze der Shell leicht überschreiten.

Git Bug?

Ich hätte erwartet, dass Folgendes funktioniert:

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

aber es tut nicht. Ich vermute, das ist ein Fehler in Git, aber vielleicht ist es beabsichtigt.

Richard Hansen
quelle
Schöne Erklärung. +1
VonC
5
Ich kam hierher, um zu wissen, wie man Mercurials macht hg log -b <branch>. Ich verstehe nicht, warum Leute sagen, dass Git unfreundlich ist. / s
weberc2
Ich weiß nicht, warum git log --all --not --exclude=refs/heads/mybranch --alles nicht funktioniert, aber es git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --allfunktioniert, mit den gleichen Einschränkungen bezüglich des Ausschlusses von KOPF und Herkunft.
Ben C
8

Schnelle Antwort:

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

Sagen wir:

  1. Dass Sie haben einen Master - Zweig

  2. Mach ein paar Commits

  3. Sie haben einen Zweig mit dem Namen b2 erstellt

  4. Tun git log -n1; Die Commit-ID ist die Zusammenführungsbasis zwischen b2 und master

  5. Machen Sie ein paar Commits in b2

  6. git log zeigt Ihren Protokollverlauf von b2 und master an

  7. Verwenden Sie den Festschreibungsbereich. Wenn Sie mit dem Konzept nicht vertraut sind, lade ich Sie ein, es zu googeln oder Überlauf zu stapeln.

    Für Ihren tatsächlichen Kontext können Sie dies beispielsweise tun

    git log commitID_FOO..comitID_BAR
    

    Das ".." ist der Bereichsoperator für den Protokollbefehl.

    Das heißt, geben Sie mir in einer einfachen Form alle Protokolle, die aktueller sind als commitID_FOO ...

  8. Schauen Sie sich Punkt 4 an, die Zusammenführungsbasis

    Also: git log COMMITID_mergeBASE..HEADzeigt dir den Unterschied

  9. Git kann die Zusammenführungsbasis für Sie so abrufen

    git merge-base b2 master
    
  10. Endlich können Sie tun:

    git log $(git merge-base master b2)..HEAD
    
Frederic Nault
quelle
4

Sie könnten so etwas versuchen:

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

Oder leihen Sie sich das Rezept im Git-Benutzerhandbuch aus :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )
John Szakmeister
quelle
+1. Ich habe in meiner Antwort geschrieben, dass Sie Commits analysieren müssen, um den Ursprung Ihres Zweigs zu finden, und Sie scheinen genau das getan zu haben.
VonC
Haben Sie log --walk-reflogs verwendet? Ich lese über diese Option und gebe mir die Ergebnisse, die ich bis jetzt brauche (noch zu testen)
dimirc
@ Dimirc Reflogs sind alle zusammen ein anderes Tier. Es zeichnet Verzweigungspunkte im Laufe der Zeit auf, im Allgemeinen zum Zweck der Wiederherstellung. Ich bin mir nicht sicher, was Sie in Ihrem Post-Receive-Hook tun, aber wenn Sie es erklären, könnten die Leute eine vernünftigere Antwort auf Ihr Problem geben.
John Szakmeister
Ich muss nur alle Commit-Nachrichten auf Knopfdruck analysieren. Der Fall, den ich behandeln möchte, ist, wenn jemand mehrere Commits am Master pusht und einen neuen Zweig mit mehreren Commits erstellt. Der Post-Receive-Hook muss die Änderungen überprüfen, die für beide Refs / Zweige vorgenommen wurden, z. B. Master und Newbranch. Ich muss die Grenzen für den neuen Zweig kennen, um zu vermeiden, dass Commit-Nachrichten zweimal analysiert werden, da sie vom Master festgeschrieben werden könnten.
Dimirc
1
In Ordnung. Dann denke ich, dass der obige Ansatz, den ich skizziert habe, wirklich das ist, was Sie wollen. Mit dem Reflog werden die Einträge nach einiger Zeit abfallen, und ich denke, das wird Ihnen Kopfschmerzen bereiten. Vielleicht möchten Sie auch die Verwendung betrachten git show-ref --tags.
John Szakmeister
4
git rev-list --exclude=master --branches --no-walk

listet die Tipps aller Zweige auf, die es nicht sind master.

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

listet jedes Commit in masterder Historie auf, das nicht in der Historie eines anderen Zweigs enthalten ist.

Die Sequenzierung ist wichtig für die Optionen, mit denen die Filterpipeline für die Auswahl von Commits eingerichtet wird. Sie --branchesmuss daher allen Ausschlussmustern --no-walkfolgen, die angewendet werden sollen, und muss den Filtern folgen, die Commits liefern. Die Rev-Liste soll nicht laufen.

jthill
quelle
4

Dadurch werden die Commits für den aktuellen Zweig ausgegeben. Wenn ein Argument übergeben wird, werden nur die Hashes ausgegeben.

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
quelle
1
Dies erzeugte ungefähr 100 irrelevante Protokollnachrichten für mich.
Arlie Stephens
Hey @ArlieStephens - Ich habe es versucht und es schien immer noch für mich zu funktionieren? Ich habe gerade Hilfe und weitere Fehlermeldungen hinzugefügt. Lass mich wissen, wie es geht!
Brad Parks
Interessant. Wenn ich mir den Code so ansehe, wie Sie ihn jetzt haben, denke ich, dass er so einfach sein kann wie das Original, vorausgesetzt, der Zweig, der mir wichtig ist, stammt vom Master. Mit dem aktuellen Code hätte ich den übergeordneten Zweig explizit angeben können. (IIRC, mein Entwickler-Zweig kam von einem Release-Zweig, nicht von Master.)
Arlie Stephens
@ArlieStephens - Ja, ich glaube nicht, dass ich irgendeine Funktionalität geändert habe. Ich habe sie noch einmal aktualisiert und die Dokumente nach einigen lokalen Tests etwas genauer gemacht. Und eine "ausführliche" Option hinzugefügt, die es zuvor gab. aber ich habe es nicht dokumentiert
Brad Parks
3

Ich benutze die folgenden Befehle:

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

oder

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

Ich fand diesen Ansatz relativ einfach.

Kasse zur Filiale und dann

  1. Lauf

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

Dies liefert nur zwei SHAs:

1) letztes Commit des Zweigs [C1]

2) und übergeordnetes Element für das erste Festschreiben des Zweigs festlegen [C2]

  1. Jetzt renn

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

Hier sind C1 und C2 zwei Zeichenfolgen, die Sie erhalten, wenn Sie den ersten Befehl ausführen. Setzen Sie diese Werte ohne <> in den zweiten Befehl.

Dies gibt eine Liste des Verlaufs der Dateiänderung innerhalb des Zweigs.

Mustkeem K.
quelle
Wenn Sie die ersten drei Zeilen der Frage lesen, werden Sie sehen, dass der Autor genau diesen Befehl auflistet und erklärt, warum es nicht das ist, wonach sie suchen
black_fm
Ah @black_fm Ich habe einige Änderungen in der Antwort vorgenommen. Sie können darüber abstimmen, wenn Sie es jetzt nützlich finden. :)
Mustkeem K
0

In meiner Situation verwenden wir Git Flow und GitHub. Dazu benötigen Sie lediglich Folgendes: Vergleichen Sie Ihren Feature-Zweig mit Ihrem Entwicklungszweig auf GitHub.

Es werden die Commits angezeigt, die nur für Ihren Feature-Zweig vorgenommen wurden.

Beispielsweise:

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

peterpengnz
quelle
Ich bin damit einverstanden, dass, wenn Sie in die Situation "Ich möchte sehen, wie eine Pull-Anfrage aussehen wird" geraten, die beste Lösung häufig darin besteht, gitGitHub zu ignorieren und stattdessen nur eine Pull-Anfrage zu stellen oder die Zweige zu vergleichen.
pkamb