611 Stimmen

So finden Sie den nächstgelegenen Elternteil eines Git-Zweigs

Nehmen wir an, ich habe das folgende lokale Repository mit einem Commit-Baum wie diesem:

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

master ist mein dies ist der neueste stabile Release-Code , develop ist mein dies ist der "nächste" Freigabecode und feature ist eine neue Funktion, die in Vorbereitung ist für develop .

Mit Hilfe von Hooks möchte ich Pushes verweigern können an feature in mein entferntes Repository zu übertragen, es sei denn f ist ein direkter Abkömmling von develop HEAD. D.h. der Commit-Baum sieht so aus, weil das Feature git rebase auf d .

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

Ist es also möglich,:

  • Identifizieren Sie den übergeordneten Zweig von feature ?
  • Identifizieren Sie die Übertragung im übergeordneten Zweig, die f ist ein Nachkomme von?

Von dort aus würde ich prüfen, was HEAD des übergeordneten Zweigs ist, und sehen, ob f Vorgänger mit dem übergeordneten Zweig HEAD übereinstimmt, um festzustellen, ob das Merkmal neu geordnet werden muss.

406voto

Chris Johnsen Punkte 199970

Angenommen, das entfernte Repository hat eine Kopie der entwickeln. Zweig (Ihre anfängliche Beschreibung beschreibt ihn in einem lokalen Repository, aber es klingt so, als ob er auch im entfernten Repository existiert), sollten Sie in der Lage sein, das zu erreichen, was ich denke, dass Sie wollen, aber der Ansatz ist ein bisschen anders als das, was Sie sich vorgestellt haben.

Die Geschichte von Git basiert auf einer DAG von Übertragungen. Branches (und "Refs" im Allgemeinen) sind nur flüchtige Markierungen, die auf bestimmte Commits in der ständig wachsenden Commit-DAG verweisen. Daher kann sich die Beziehung zwischen Zweigen im Laufe der Zeit ändern, nicht aber die Beziehung zwischen Commits.

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

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

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

Jetzt sieht es so aus baz stützt sich auf foo . Aber die Abstammung von baz hat sich nicht geändert. Wir haben lediglich ein Etikett (und die daraus resultierende hängende Übergabe) entfernt. Und was ist, wenn wir ein neues Label hinzufügen bei 4 ?

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

Jetzt sieht es so aus baz stützt sich auf quux . Doch die Abstammung hat sich nicht geändert, nur die Bezeichnungen haben sich geändert.

Wenn wir jedoch die Frage stellen würden: "Ist Commit 6 ein Nachkomme von commit 3 ?" (unter der Annahme, dass 3 et 6 vollständige SHA-1 Commit-Namen sind), dann wäre die Antwort "ja", egal ob die bar et quux Etiketten vorhanden sind oder nicht.

Man könnte also Fragen stellen wie "ist die geschobene Übergabe ein Nachkomme der aktuellen Spitze der entwickeln. Zweig?", aber Sie können nicht zuverlässig fragen: "Was ist der übergeordnete Zweig der gepushten Übertragung?".

Eine meist zuverlässige Frage, die dem Gewünschten nahe zu kommen scheint, ist die folgende:

Für alle Vorgänger der gepushten Übertragung (mit Ausnahme der aktuellen Spitze von entwickeln. und seine Vorfahren), die die aktuelle Spitze von entwickeln. als Elternteil:

  • gibt es mindestens eine solche Verpflichtung?
  • Sind alle diese Commits Single-Eltern-Commits?

Dies könnte wie folgt umgesetzt werden:

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 einiges von dem abdecken, was Sie eingeschränkt haben möchten, aber vielleicht nicht alles.

Als Referenz finden Sie hier ein ausführliches Beispiel:

    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 könnte verwendet werden, um Folgendes abzulehnen H et S bei Annahme H' , J , K ou N aber sie würde auch akzeptieren L et P (sie beinhalten Verschmelzungen, aber sie verschmelzen nicht die Spitze der entwickeln. ).

Auch zurückweisen L et P können Sie die Frage ändern und fragen

Für alle Vorgänger der gepushten Übergabe (außer der aktuellen Spitze von entwickeln. und seine Vorfahren):

  • Gibt es Pendler mit zwei Elternteilen?
  • wenn nicht, hat mindestens eine dieser Übertragungen die aktuelle Spitze von entwickeln. sein (einziges) Elternteil?
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

389voto

Joe Chrysler Punkte 3410

Eine Umformulierung

Man könnte die Frage auch so formulieren: "Welches ist der nächste Commit, der sich in einem anderen Zweig als dem aktuellen befindet, und welcher ist das?"

Eine Lösung

Sie finden es mit ein wenig Magie in der Befehlszeile

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 )}'

Und so funktioniert es:

  1. Zeigt einen textuellen Verlauf aller Übertragungen an, einschließlich entfernter Zweige.
  2. Die Vorgänger der aktuellen Übertragung sind mit einem Stern gekennzeichnet. Alles andere wird herausgefiltert.
  3. Ignoriert alle Übertragungen im aktuellen Zweig.
  4. Das erste Ergebnis ist der nächstgelegene Vorfahrenzweig. Ignorieren Sie die anderen Ergebnisse.
  5. Die Namen der Zweige werden [in Klammern] angezeigt. Ignorieren Sie alles, was außerhalb der Klammern steht, und die Klammern.
  6. Manchmal enthält der Name der Verzweigung ein ~# ou ^# um anzugeben, wie viele Commits zwischen dem referenzierten Commit und dem Branch Tip liegen. Das ist uns egal. Ignorieren Sie sie.

Und die résultat

Die Ausführung des obigen Codes auf

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

Sie erhalten develop wenn Sie es von H aus ausführen und master wenn Sie es von I. aus betreiben.

Der Code ist als Gist verfügbar .

206voto

NIKHIL C M Punkte 3125

Git-Elternteil

Sie können einfach den Befehl

git parent

um den übergeordneten Zweig zu finden, wenn Sie die Die Antwort von Joe Chrysler als Git-Alias . Das wird die Nutzung vereinfachen.

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

vim  ~/.gitconfig

Fügen Sie den folgenden Alias-Befehl in die Datei ein:

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

Speichern Sie und beenden Sie den Editor.

Führen Sie den Befehl git parent .

Das war's!

183voto

rcde0 Punkte 3802

Sie können auch versuchen:

git log --graph --decorate

20 Stimmen

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

71voto

Murali Mopuru Punkte 5466

Das funktioniert bei mir einwandfrei:

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

Höfliche Kommentare und Antworten von droidbot und @Jistanidiot.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X