Wie finde ich das nächste Elternteil eines Git-Zweigs?


418

Angenommen, ich habe das folgende lokale Repository mit einem Commit-Baum wie diesem:

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

masterist mein dies der letzte Version Code ist , developist meine dies der ‚nächste‘ Freigabecode ist , und featureist eine neue Funktion für vorbereitetdevelop .

Was ich mit Hooks auf meinem Remote-Repo tun möchte, ist, dass Pushs featureabgelehnt werden, es sei denn, Commit fist ein direkter Nachkomme von developHEAD. dh der Baum wie folgt aussieht begehen , weil Funktion wurde git rebaseauf d.

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

So ist es möglich:

  • Identifizieren Sie den übergeordneten Zweig von feature?
  • Identifizieren Sie das Commit im übergeordneten Zweig, von dem fein Nachkomme stammt.

Von dort aus würde ich überprüfen, was HEAD des übergeordneten Zweigs ist, und prüfen, ob der fVorgänger mit dem HEAD des übergeordneten Zweigs übereinstimmt, um festzustellen, ob das Feature neu basiert werden muss.


Diese Frage sollte umformuliert werden, um den Elternteil eines Elternteils zu finden.
Tim Boland

Antworten:


346

Angenommen, das Remote-Repository verfügt über eine Kopie des Entwicklungszweigs (Ihre ursprüngliche Beschreibung beschreibt sie in einem lokalen Repository, es scheint jedoch auch in der Remote vorhanden zu sein), sollten Sie in der Lage sein, das zu erreichen, was ich denke, aber den Ansatz ist ein bisschen anders als Sie es sich vorgestellt haben.

Die Geschichte von Git basiert auf einer DAG von Commits. Zweige (und „Refs“ im Allgemeinen) sind nur vorübergehende Bezeichnungen, die auf bestimmte Commits in der kontinuierlich wachsenden Commit-DAG verweisen. Daher kann die Beziehung zwischen Zweigen im Laufe der Zeit variieren, die Beziehung zwischen Commits jedoch nicht.

    ---o---1                foo
            \
             2---3---o      bar
                  \
                   4
                    \
                     5---6  baz

Es sieht so aus, als ob bazes auf (einer alten Version von) basiert bar? Aber was ist, wenn wir löschen bar?

    ---o---1                foo
            \
             2---3
                  \
                   4
                    \
                     5---6  baz

Jetzt sieht es so aus, als ob bazes auf basiert foo. Aber die Abstammung von bazhat sich nicht geändert, wir haben nur ein Etikett entfernt (und das daraus resultierende baumelnde Commit). Und was ist, wenn wir bei ein neues Label hinzufügen 4?

    ---o---1                foo
            \
             2---3
                  \
                   4        quux
                    \
                     5---6  baz

Jetzt sieht es so aus, als ob bazes auf basiert quux. Die Abstammung änderte sich jedoch nicht, nur die Beschriftungen änderten sich.

Wenn wir jedoch fragten: "Ist Commit 6ein Nachkomme von Commit 3?" (vorausgesetzt , 3und 6sind voll SHA-1 Namen begehen), dann wäre die Antwort „ja“ lautet, ob die barund quuxEtiketten vorhanden sind oder nicht.

Sie könnten also Fragen stellen wie "Ist das Push-Commit ein Nachkomme der aktuellen Spitze des Entwicklungszweigs ?", Aber Sie können nicht zuverlässig fragen: "Was ist der übergeordnete Zweig des Push-Commits?".

Eine meist verlässliche Frage, die sich Ihren Wünschen zu nähern scheint, lautet:

Für alle Vorfahren des Push-Commits (mit Ausnahme des aktuellen Entwicklungstipps und seiner Vorfahren), die den aktuellen Entwicklungstipp als übergeordnetes Element haben:

  • Gibt es mindestens ein solches Commit?
  • Sind alle diese Commits Single-Parent-Commits?

Welches könnte implementiert werden als:

pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_children_of_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
    ,)     echo "must descend from tip of '$basename'"
           exit 1 ;;
    ,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
           exit 1 ;;
    ,*)    exit 0 ;;
esac

Dies wird einige der von Ihnen gewünschten Einschränkungen abdecken, aber möglicherweise nicht alles.

Als Referenz finden Sie hier eine erweiterte Beispielhistorie:

    A                                   master
     \
      \                    o-----J
       \                  /       \
        \                | o---K---L
         \               |/
          C--------------D              develop
           \             |\
            F---G---H    | F'--G'--H'
                    |    |\
                    |    | o---o---o---N
                     \   \      \       \
                      \   \      o---o---P
                       \   \   
                        R---S

Der obige Code kann verwendet werden , um abzulehnen Hund Swährend der Annahme H', J, K, oder N, aber es wäre auch zu akzeptieren , Lund P(sie beinhalten verschmilzt, aber sie verschmelzen nicht mit der Spitze entwickeln ).

Um auch Lund abzulehnen P, können Sie die Frage ändern und stellen

Für alle Vorfahren des Push-Commits (mit Ausnahme des aktuellen Entwicklertipps und seiner Vorfahren):

  • Gibt es irgendwelche Verpflichtungen mit zwei Eltern?
  • Wenn nicht, hat mindestens ein solches Commit den aktuellen Tipp , sein (einziges) Elternteil zu entwickeln?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_commits_beyond_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
    *\ *)          echo "must not push merge commits (rebase instead)"
                   exit 1 ;;
    *"$baserev"*)  exit 0 ;;
    *)             echo "must descend from tip of '$basename'"
                   exit 1 ;;
esac

Ich verstehe Folgendes: git: fatal: mehrdeutiges Argument '...': sowohl Revision als auch Dateiname. Was ist die Absicht der dreifachen Punkte?
Jack Ukleja

1
@Schneider Ich bin mir ziemlich sicher, dass das '...' in diesem Beispiel ein Platzhalter sein soll: Wenn Sie es durch den SHA des Commits ersetzen, versuchen Sie, diese Prüfung anhand (z. B. dem HEAD des Zweigs) durchzuführen Sie sind gerade auf), alles funktioniert gut.
Daniel Brady

Vielen Dank für diese ausführliche Antwort! Es ist super nützlich. Ich möchte einen ähnlichen Hook erstellen, aber ich möchte den Namen des Entwicklungszweigs nicht fest codieren. Das heißt, ich möchte einen Hook, um zu verhindern, dass ein anderer Zweig als der übergeordnete Zweig wiederhergestellt wird. Wenn ich Ihre Antwort gut verstehe (ich bin neu in Bash und so), wird dies in Ihrer Antwort nicht behandelt, oder? Gibt es eine Möglichkeit, dies zu tun?
Kemeia

Sind Sie bereit, eine verwandte Frage zu beantworten? Ich konnte Ihren Code nicht für ein REMOTE-Repository verwenden. Hier ist der Link zur Folgefrage, wie Sie Ihren Ansatz an die Arbeit mit einem REMOTE-Repository anpassen können: stackoverflow.com/questions/49619492/…
CodeMed

Dies funktionierte nicht für mich, als ich hatte develop > release > feature, ich würde mich wieder entwickeln und es erfordert die Kenntnis der Eltern. Die Lösung für mein Problem war stackoverflow.com/a/56673640/2366390
verdverm

240

Eine Umformulierung

Eine andere Möglichkeit, die Frage zu formulieren, lautet: "Was ist das nächste Commit, das sich in einem anderen Zweig als dem aktuellen Zweig befindet, und welcher Zweig ist das?"

Eine Lösung

Sie können es mit ein wenig Befehlszeilenmagie finden

git show-branch \
| sed "s/].*//" \
| grep "\*" \
| grep -v "$(git rev-parse --abbrev-ref HEAD)" \
| head -n1 \
| sed "s/^.*\[//" 

Mit awk :

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

So funktioniert das:

  1. Zeigen Sie einen Textverlauf aller Commits an, einschließlich Remote-Zweige.
  2. Vorfahren des aktuellen Commits sind durch einen Stern gekennzeichnet. Alles andere herausfiltern.
  3. Ignorieren Sie alle Commits im aktuellen Zweig.
  4. Das erste Ergebnis ist der nächste Ahnenzweig. Ignorieren Sie die anderen Ergebnisse.
  5. Zweignamen werden [in Klammern] angezeigt. Ignorieren Sie alles außerhalb der Klammern und der Klammern.
  6. Manchmal enthält der Filialname ein ~ # oder ^ #, um anzugeben, wie viele Commits zwischen dem referenzierten Commit und dem Branchentipp liegen. Es ist uns egal. Ignoriere sie.

Und das Ergebnis

Führen Sie den obigen Code aus

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

Wird Ihnen geben, developwenn Sie es von H masterausführen und wenn Sie es von I ausführen.

Der Code ist als Kern verfügbar


24
Ein nachfolgendes Backtick, das einen Fehler verursacht hat, wurde entfernt. Wenn ich diesen Befehl ausführe, erhalte ich eine große Anzahl von Warnungen, die sich über jeden Zweig beschweren und sagencannot handle more than 25 refs
Jon L.

1
@JoeChrysler glauben Sie , kann es statt 2 eine Zeile machen, und es möglicherweise auf Mac funktioniert wie ackauf dem Mac nicht verfügbar ist (jemand vorschlug ersetzt ackmit grep)
nonopolarity

53
Entschuldigung, das ist falsch. Hier ist die richtige, die für mich funktioniert hat:git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
Droidbot

15
@droidbot Schön, muss aber neu angeordnet werden, um das Entfernen von Refs zu vermeiden, wenn grep -v eine Commit-Nachricht abfängt oder Ihr Filialname Teil eines anderen Filialnamens ist. git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
Gaal

3
@OlegAbrazhaev Ich weiß nicht, ob Sie jemals Ihre Frage beantwortet bekommen haben. mit dem git alias von: parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"funktioniert für mich
mduttondev

111

Sie können auch versuchen:

git log --graph --decorate

5
git log --graph --decorate --simplify-by-decorationwo --graphist optional.
Na13-c

1
git log --graph --decorate --simplify-by-decoration --oneline
Anishtain4

106

Git Elternteil

Sie können den Befehl einfach ausführen

git parent

Um das übergeordnete Element des Zweigs zu finden, fügen Sie die Antwort von @Joe Chrysler als Git-Alias ​​hinzu . Dies vereinfacht die Verwendung.

Öffnen Sie die gitconfig-Datei "~/.gitconfig"unter mit einem beliebigen Texteditor. (Für Linux). Und für Windows befindet sich der Pfad ".gitconfig" im Allgemeinen unterc:\users\your-user\.gitconfig

vim  ~/.gitconfig

Fügen Sie der Datei den folgenden Alias-Befehl hinzu:

[alias]
            parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"

Speichern und beenden Sie den Editor.

Führen Sie den Befehl aus git parent

Das ist es!


5
Dies ist eine großartige Lösung. Es wäre hilfreich, auch einige Beispielausgaben hinzuzufügen, um die erwarteten Ergebnisse zu gewährleisten. Als ich es ausführte, erhielt ich vor der allerletzten Zeile einige Warnungen, von denen ich glaube, dass sie der Name des übergeordneten Zweigs waren.
Tempel

4
Klappt wunderbar! Für Windows-Benutzer befindet sich die .gitconfig im Allgemeinen unter c: \ users \ your-user \ .gitconfig
zion

12
Erste cannot handle more than 25 refsAusnahme.
Shajin

Kann jemand dies bearbeiten, um die Warnung zu verarbeiten? @ttemple, kannst du?
NIKHIL CM

@NIKHILCM arbeitet wie ein Champion. Aber ich habe hier eine Frage, ob der Elternteil angibt, woher der Zweig stammt, oder etwas anderes?
Hariprasath

52

Ich habe eine Lösung für Ihr Gesamtproblem (stellen Sie fest, ob featurees von der Spitze von abstammt develop), aber es funktioniert nicht mit der von Ihnen beschriebenen Methode.

Sie können verwenden, git branch --containsum alle Zweige aufzulisten, die von der Spitze von abstammen develop, und dann verwenden grep, um sicherzustellen, dass sie featurezu ihnen gehören.

git branch --contains develop | grep "^ *feature$"

Wenn es unter ihnen ist, wird es " feature"auf die Standardausgabe gedruckt und hat einen Rückkehrcode von 0. Andernfalls wird nichts gedruckt und ein Rückkehrcode von 1.


1
Dies funktioniert, aber es sollte beachtet werden, dass es in einem Repository mit vielen Refs lange dauern kann. Das macht es ein bisschen weniger als ideal zum Einlaufen, z. B. in einen Pre-Receive-Hook.
ebneter

Ich habe nach der Filiale gesucht, wir nennen sie <branch>, wo ich aufgetreten bin : git checkout -b <branch-2>von ... DAS ist die Antwort! Eigentlich keine Notwendigkeit für grep. git branch --contains <branch>
Poopy McFartnoise

44

Das funktioniert gut für mich.

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Mit freundlicher Genehmigung von: @droidbot und @Jistanidiot


Ja, aber manchmal bekommt man "kaputte Pfeife" von grep.
Vladislav Rastrusny

1
*ist kein richtiger Regex, um an grep weiterzugeben. Sollte verwenden grep -F '*'oder grep '\*'stattdessen. Ansonsten gute Lösung.
Arielf

Ich habe keine Ausgabe.
Sandip Subedi

funktioniert für mich ....
roottraveller

11

Da keine der oben genannten Antworten in unserem Repository funktioniert hat, möchte ich meinen eigenen Weg mit den neuesten Zusammenführungen in git log: teilen.

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

Fügen Sie es in ein Skript mit dem Namen ein git-last-merges, das auch einen Zweignamen als Argument (anstelle des aktuellen Zweigs) sowie andere git logArgumente akzeptiert

Anhand der Ausgabe können wir die übergeordneten Zweige manuell anhand der eigenen Verzweigungskonventionen und der Anzahl der Zusammenführungen aus jedem Zweig erkennen.

BEARBEITEN: Wenn Sie git rebasehäufig untergeordnete Zweige verwenden (und Zusammenführungen häufig vorgespult werden, damit nicht zu viele Zusammenführungs-Commits vorhanden sind), funktioniert diese Antwort nicht gut. Daher habe ich ein Skript geschrieben, um Commits im Voraus zu zählen (normal und Zusammenführen). und hinter Commits (es sollte keine Hinterzusammenführung im übergeordneten Zweig geben) in allen Zweigen im Vergleich zum aktuellen Zweig. Führen Sie einfach dieses Skript aus und lassen Sie mich wissen, ob es für Sie funktioniert oder nicht

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n

Vielen Dank. Dies funktioniert zwar möglicherweise nicht sehr gut, wenn Sie es rebasehäufig verwenden (und Zusammenführungen werden fast-forwardhäufig bearbeitet ). Ich werde meine Antwort bearbeiten, wenn ich eine bessere Lösung gefunden habe.
Saeedgnu

1
Das einzige? Antwort bisher hat das für mich sinnvoll funktioniert, wenn der aktuelle Zweig der Meister ist. Die meisten anderen Lösungen ergaben ein zufälliges (und eindeutig falsches) Ergebnis in diesem zugegebenermaßen Randfall, in dem es keine tatsächlichen übergeordneten Zweige gibt.
Arielf

Dies ist die einzige Antwort, die für mich funktioniert hat. Um den ersten Elternteil anstelle einer Liste der ersten 10 zu erhalten, können Sie git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
Folgendes

10

Eine Lösung

Die auf basierend basierendegit show-branch Lösung hat bei mir nicht ganz funktioniert (siehe unten), daher habe ich sie mit der aufgit log und basierenden Lösung kombiniert und am Ende Folgendes erhalten :

git log --decorate --simplify-by-decoration --oneline \ # selects only commits with a branch or tag
      | grep -v "(HEAD" \                               # removes current head (and branch)
      | head -n1 \                                      # selects only the closest decoration
      | sed 's/.* (\(.*\)) .*/\1/' \                    # filters out everything but decorations
      | sed 's/\(.*\), .*/\1/' \                        # picks only the first decoration
      | sed 's/origin\///'                              # strips "origin/" from the decoration

Einschränkungen und Vorsichtsmaßnahmen

  • HEAD kann getrennt werden (viele CI-Tools tun dies, um sicherzustellen, dass sie in einem bestimmten Zweig ein korrektes Commit erstellen), aber der Ursprungszweig und der lokale Zweig müssen beide gleich oder "über" dem aktuellen HEAD sein.
  • Es dürfen keine Tags im Weg sein (ich nehme an; ich habe das Skript nicht bei Commits mit einem Tag zwischen untergeordnetem und übergeordnetem Zweig getestet).
  • Das Skript basiert auf der Tatsache, dass "HEAD" vom Befehl immer als erste Dekoration aufgeführt wirdlog
  • läuft das Skript auf masterunddevelop Ergebnisse (meist) in<SHA> Initial commit

Die Ergebnisse

 A---B---D---E---F <-origin/master, master
      \      \
       \      \
        \      G---H---I <- origin/hotfix, hotfix
         \
          \
           J---K---L <-origin/develop, develop
                \
                 \
                  M---N---O <-origin/feature/a, feature/a
                       \   \
                        \   \
                         \   P---Q---R <-origin/feature/b, feature/b
                          \
                           \
                            S---T---U <-origin/feature/c, feature/c

Trotz der Existenz einer lokalen Verzweigung (z. B. nur origin/topicvorhanden, da das Commit Odirekt von der SHA ausgecheckt wurde) sollte das Skript wie folgt gedruckt werden:

  • Für Commits G, H,I (Zweig hotfix) →master
  • Für Commits M, N,O (Zweig feature/a) →develop
  • Für Commits S, T,U (Zweig feature/c) →develop
  • Für Commits P, Q,R (Zweig feature/b) →feature/a
  • Für Commits J, K, L(Zweig develop) → <sha> Initial commit*
  • Für Commits B, D, E, F(Zweig master) →<sha> Initial commit

* - oder masterwenn developdie Commits über dem HEAD des Masters liegen (~ der Master kann schnell weiterentwickelt werden)


Warum hat Show-Branch nicht für mich gearbeitet?

Die auf basierendegit show-branch Lösung erwies sich für mich in folgenden Situationen als unzuverlässig:

  • Abgenommener KOPF - einschließlich abgenommenem Kopfgehäuse bedeutet Ersetzen grep '\*' \durch "grep"! \ - und das ist erst der Anfang aller Probleme
  • Ausführen des Skripts auf masterunddevelop führt zu developbzw. ``
  • Zweige aufmaster Zweig ( hotfix/Zweige) enden mit dem developals Elternteil, da ihr nächster masterZweig Elternteil mit !anstatt aus *einem Grund markiert wurde .

2
Nur Antwort, die funktioniert hat - als Git-Alias:"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Ian Kemp

8

Denken Sie daran, dass Sie, wie unter "Git: Finden, von welchem ​​Zweig ein Commit stammt" beschrieben sind , den Zweig, in dem dieser Commit durchgeführt wurde, nicht einfach bestimmen können (Zweige können umbenannt, verschoben, gelöscht ... werden), obwohl dies git branch --contains <commit>ein Anfang ist.

  • Sie können von Commit zu Commit zurückkehren, bis git branch --contains <commit>der featureZweig und der Zweig nicht mehr developaufgelistet sind.
  • Vergleichen Sie das Commit SHA1 mit /refs/heads/develop

Wenn die beiden Commits übereinstimmen, können Sie loslegen (dies würde bedeuten, dass der featureZweig seinen Ursprung im HEAD of hat develop).


6

JoeChryslers Befehlszeilenmagie kann vereinfacht werden. Hier ist Joes Logik: Der Kürze halber habe ich in beiden Versionen einen Parameter eingeführt, der cur_branchanstelle der Befehlssubstitution benannt wurde `git rev-parse --abbrev-ref HEAD`. das kann so initialisiert werden:

cur_branch=$(git rev-parse --abbrev-ref HEAD)

Dann ist hier Joes Pipeline:

git show-branch -a           |
  grep '\*'                  | # we want only lines that contain an asterisk
  grep -v "$cur_branch"      | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed

Wir können dasselbe wie alle fünf dieser einzelnen Befehlsfilter in einem relativ einfachen awkBefehl erreichen:

git show-branch -a |
  awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  

Das bricht so zusammen:

-F'[]^~[]' 

teilen Sie die Zeile in Felder auf ], ^, ~und [Zeichen.

/\*/                      

Suchen Sie nach Zeilen, die ein Sternchen enthalten

&& !/'"$cur_branch"'/

... aber nicht der aktuelle Filialname

{ print $2;               

Wenn Sie eine solche Zeile finden, drucken Sie das zweite Feld (dh den Teil zwischen dem ersten und dem zweiten Vorkommen unserer Feldtrennzeichen). Bei einfachen Zweignamen ist dies genau das, was sich in den Klammern befindet. Bei Refs mit relativen Sprüngen ist dies nur der Name ohne Modifikator. Unser Satz von Feldtrennzeichen behandelt also die Absicht beider sedBefehle.

  exit }

Dann sofort beenden. Dies bedeutet, dass immer nur die erste übereinstimmende Zeile verarbeitet wird, sodass wir die Ausgabe nicht durchleiten müssen head -n 1.


3
Beachten Sie, dass einige Zweige aufgrund zu vieler Refs in der Ausgabe fehlen können. Sie werden stattdessen als Warnungen auf stderr angezeigt.
Zitrax

5

Hier ist eine PowerShell-Implementierung der Mark Reed-Lösung:

git show-branch -a | where-object { $_.Contains('*') -eq $true} | Where-object {$_.Contains($branchName) -ne $true } | select -first 1 | % {$_ -replace('.*\[(.*)\].*','$1')} | % { $_ -replace('[\^~].*','') }

5

Ich sage nicht, dass dies ein guter Weg ist, um dieses Problem zu lösen, aber dies scheint für mich zu funktionieren.

git branch --contains $(cat .git/ORIG_HEAD) Das Problem ist, dass das Cat'ing einer Datei in das Innenleben von Git hineinschaut, sodass dies nicht unbedingt vorwärtskompatibel (oder abwärtskompatibel) ist.


3

Plattformübergreifende Implementierung mit Ant

    <exec executable="git" outputproperty="currentBranch">
        <arg value="rev-parse" />  
        <arg value="--abbrev-ref" />  
        <arg value="HEAD" />  
    </exec>

    <exec executable="git" outputproperty="showBranchOutput">
        <arg value="show-branch" />  
        <arg value="-a" />  
    </exec>

    <loadresource property="baseBranch">
      <propertyresource name="showBranchOutput"/>
          <filterchain>
            <linecontains>
              <contains value="*"/>
            </linecontains>
            <linecontains negate="true">
              <contains value="${currentBranch}"/>
            </linecontains>
            <headfilter lines="1"/>
            <tokenfilter>
                <replaceregex pattern=".*\[(.*)\].*" replace="\1"/>
                <replaceregex pattern="[\^~].*" replace=""/>
            </tokenfilter>
          </filterchain>
    </loadresource>

    <echo message="${currentBranch} ${baseBranch}" />

2

@ Mark Reed: Sie sollten hinzufügen, dass die Festschreibungszeile nicht nur ein Sternchen enthalten sollte, sondern mit einem Sternchen beginnen sollte! Andernfalls werden Commit-Nachrichten, die ein Sternchen enthalten, ebenfalls in die übereinstimmenden Zeilen aufgenommen. So sollte es sein:

git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'

oder die lange Version:

git show-branch -a           |
  awk '^\*'                  | # we want only lines that contain an asterisk
  awk -v "$current_branch"   | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed`

2
vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Erreicht die gleichen Ziele wie Mark Reeds Antwort, verwendet jedoch einen viel sichereren Ansatz, der sich in einer Reihe von Szenarien nicht schlecht verhält:

  1. Das letzte Commit des übergeordneten Zweigs ist eine Zusammenführung, sodass die Spalte - nicht angezeigt wird*
  2. Die Commit-Nachricht enthält den Filialnamen
  3. Commit-Nachricht enthält *

0

Wer dies heutzutage tun möchte - Die SourceTree-Anwendung von Atlassian zeigt Ihnen eine hervorragende visuelle Darstellung der Beziehung Ihrer Filialen zueinander, dh wo sie begonnen haben und wo sie sich derzeit in der Festschreibungsreihenfolge befinden (z. B. HEAD oder 4 Festschreibungen dahinter usw.). .


0

Wenn Sie den Quellbaum verwenden, sehen Sie sich Ihre Festschreibungsdetails> Eltern> an. Die Festschreibungsnummern sind unterstrichen (Links).


0

Eine Alternative: git rev-list master | grep "$(git rev-list HEAD)" | head -1

Holen Sie sich das letzte Commit, das sowohl mein Zweig als auch master(oder welcher Zweig auch immer Sie angeben möchten) ist.


0

Dies funktionierte nicht für mich, als ich so etwas getan hatte develop > release-v1.0.0 > feature-foo, es würde den ganzen Weg zurückgehen, um sich zu entwickeln. Beachten Sie, dass es sich um eine Rebase handelte, nicht sicher, ob dies mein Problem verschärft ...

Das Folgende hat mir den richtigen Commit-Hash gegeben

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.