web-dev-qa-db-de.com

Wie finde ich das nächste Commit in git? (Kind/Kinder von Ref)

ref^ bezieht sich auf das Festschreiben vor ref. Wie wäre es mit dem Festschreiben afterref?

Zum Beispiel, wenn ich git checkout 12345, wie checke ich das nächste Commit aus?

Vielen Dank.

PS Ja, git einen DAG-Knotenzeiger-Strukturbaum. Wie finde ich das Commit nach diesem?

189
Schwern

Um alle Commits aufzulisten, beginnend mit dem aktuellen und dem untergeordneten Element usw. - im Grunde genommen Standard-Git-Protokoll, aber in der Zeit andersherum, verwenden Sie so etwas

git log --reverse --ancestry-path 894e8b4e93d8f3^..master

dabei ist 894e8b4e93d8f3 der erste Commit, den Sie anzeigen möchten.

158
Tim Hunt

Der Schöpfer für Hudson (jetzt Jenkins) Kohsuke Kawaguchi wurde gerade veröffentlicht (November 2013):
kohsuke/git-children-of :

Bei einem Commit finden Sie unmittelbare Kinder dieses Commits.

#!/bin/bash -e
# given a commit, find immediate children of that commit.
for arg in "[email protected]"; do
  for commit in $(git rev-parse $arg^0); do
    for child in $(git log --format='%H %P' --all | grep -F " $commit" | cut -f1 -d' '); do
      git describe $child
    done
  done
done

Wie durch diesen Thread veranschaulicht, gibt es in einem VCS, das auf einer durch DAG (Directed Acyclic Graph) dargestellten Geschichte basiert, nicht "ein Elternteil" oder "ein Kind".

        C1 -> C2 -> C3
      /               \
A -> B                  E -> F
      \               /
        D1 -> D2 ----/

Die Reihenfolge der Commits erfolgt nach "topo-order" oder "date-order" (siehe GitPro-Buch )

Aber seit Git1.6.0 können Sie die Kinder eines Commits auflisten.

git rev-list --children
git log --children

Hinweis: Für übergeordnete Commits haben Sie dasselbe Problem, wobei das Suffix ^ zu einem Revisionsparameter für das übergeordnete first dieses Commit-Objekts steht. ^<n> bezeichnet den <n>th-Elternteil (d. h. rev^ entspricht rev^1).

Wenn Sie sich in Zweig foo befinden und "git merge bar" ausgeben, wird foo das erste übergeordnete Element sein.
.E: Das erste übergeordnete Element ist der Zweig, in dem Sie sich befanden, als Sie zusammengeführt wurden, und der zweite ist das Commit für den Zweig, in dem Sie zusammengeführt wurden.

30
VonC

was ich gefunden habe ist

git rev-list --ancestry-path commit1..commit2

dabei setze ich commit1 als aktuellen Commit und commit2 für den aktuellen Kopf. Dies liefert mir eine Liste aller Commits, die einen Pfad zwischen commit1 und commit2 bilden.

Die letzte Zeile der Ausgabe ist das untergeordnete Element von commit1 (auf dem Pfad zu commit2).

17
white_gecko

Ich weiß, was du meinst. Es ist frustrierend, reichlich Syntax zu haben, um zu vorherigen Commits zu gelangen, aber keine zu den nächsten. In einer komplexen Geschichte wird das Problem "Was ist das nächste Commit" ziemlich hart, aber bei der komplexen Verschmelzung tritt die gleiche Härte auch bei "vorherigen" Commits auf. Im einfachen Fall wäre es innerhalb eines einzelnen Zweigs mit linearer Historie (auch lokal nur für eine begrenzte Anzahl von Commits) schön und sinnvoll, vorwärts und rückwärts zu gehen.

Das eigentliche Problem dabei ist jedoch, dass die untergeordneten Commits nicht referenziert werden, sondern nur eine rückwärts verknüpfte Liste. Um das Child-Commit zu finden, wird eine Suche durchgeführt, die zwar nicht zu schlecht ist, aber wahrscheinlich nicht etwas, das GIT in die refspec-Logik einbauen möchte.

Jedenfalls bin ich auf diese Frage gestoßen, weil ich einfach in der Historie einen Commit zu einem Zeitpunkt vorgehen und Tests machen möchte, und manchmal muss man einen Schritt nach vorn und nicht zurück machen. Nun, mit einigem Nachdenken kam ich zu dieser Lösung:

Wählen Sie ein Commit aus, wo Sie sich gerade befinden. Dies könnte wahrscheinlich ein Zweigleiter sein. Wenn Sie sich in Branch ~ 10 befinden, dann "git checkout branch ~ 9" Dann "git checkout branch ~ 8", um das nächste zu erhalten. Dann "git checkout branch ~ 7" usw.

Das Dekrementieren der Nummer sollte in einem Skript sehr einfach sein, wenn Sie es brauchen. Viel einfacher als das Analysieren der Git-Rev-Liste.

7
vontrapp

Es gibt kein eindeutiges "next commit". Da der Verlauf in Git eine DAG und keine Zeile ist, können viele Commits ein gemeinsames Parent (Zweige) und Commits mehrere (Merges) haben.

Wenn Sie einen bestimmten Zweig vor Augen haben, können Sie sich das Protokoll ansehen und sehen, in welchem ​​Commit der aktuelle Ordner als übergeordnetes Element aufgeführt ist.

6
Phil Miller

Zwei praktische Antworten:

Ein Kind

Basierend auf @ Michaels Antwort habe ich den Alias ​​child in meinem .gitconfig gehackt.

Es funktioniert wie erwartet im Standardfall und ist auch vielseitig.

# Get the child commit of the current commit.
# Use $1 instead of 'HEAD' if given. Use $2 instead of curent branch if given.
child = "!bash -c 'git log --format=%H --reverse --ancestry-path ${1:-HEAD}..${2:\"$(git rev-parse --abbrev-ref HEAD)\"} | head -1' -"

Es gibt standardmäßig das Kind von HEAD an (es sei denn, es wird ein anderes Commit-ish-Argument angegeben), indem Sie der Abstammung einen Schritt in Richtung der Spitze des aktuellen Zweigs folgen (sofern kein anderes Commit-ish als zweites Argument angegeben wird).

Verwenden Sie %h anstelle von %H, wenn Sie das kurze Hash-Formular verwenden möchten.

Mehrere Kinder

Mit einem freistehenden HEAD (es gibt keinen Zweig) oder um alle Kinder unabhängig vom Zweig zu bekommen:

# For the current (or specified) commit-ish, get the all children, print the first child 
children = "!bash -c 'c=${1:-HEAD}; set -- $(git rev-list --all --not \"$c\"^@ --children | grep $(git rev-parse \"$c\") ); shift; echo $1' -"

Ändern Sie den $1 in $*, um alle untergeordneten Elemente zu drucken.

Sie können auch --all in ein Festschreibungswort ändern, um nur die Kinder anzuzeigen, die Vorfahren dieser Festschreibung sind, mit anderen Worten, nur die Kinder "in Richtung" des angegebenen Festschreibens anzuzeigen. Dies kann helfen, die Ausgabe von vielen Kindern auf ein einziges zu beschränken.

5
Tom Hale

Ich habe viele verschiedene Lösungen ausprobiert und keine hat bei mir funktioniert. Musste mit meinen eigenen kommen.

nächstes Commit finden

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

finde vorheriges Commit

function p() {
    git checkout HEAD^1
}
4
M K

Wenn Sie kein bestimmtes Ziel festlegen möchten, stattdessen untergeordnete Commits anzeigen möchten, die möglicherweise aufanybranch liegen, können Sie diesen Befehl verwenden:

git rev-list --children --all | grep ^${COMMIT}

Wenn Sie alle Kinderund Enkelkindersehen möchten, müssen Sie rev-list --children wie folgt rekursiv verwenden:

git rev-list --children --all | \
egrep ^\($(git rev-list --children --all | \
           grep ^${COMMIT} | \
           sed 's/ /|/g')\)

(Die Version, die nur Enkelkinder gibt, würde eine komplexere sed und/oder cut verwenden.)

Zum Schluss können Sie das in einen log --graph-Befehl einspeisen, um die Baumstruktur zu sehen:

git log --graph --oneline --decorate \
\^${COMMIT}^@ \
$(git rev-list --children --all | \
  egrep ^\($(git rev-list --children --all | \
             grep ^${COMMIT} | \
             sed 's/ /|/g')\))
4
Matt McHenry

Ich habe diesen Alias ​​in ~/.gitconfig

first-child = "!f() { git log  --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"
3
weakish

Wenn die untergeordneten Commits sich alle in einem Zweig befinden, können Sie gitk --all commit^.. verwenden. Wenn beispielsweise SHIT-1 des Commits c6661c5 lautet, geben Sie gitk --all c6661c5^.. ein.

Sie müssen wahrscheinlich den vollständigen SHA-1 in gitks Zelle "SHA1 ID:" eingeben. Sie benötigen den vollständigen SHA-1, den Sie für dieses Beispiel über git rev-parse c6661c5 erhalten können.

Alternativ erzeugt git rev-list --all --children | grep '^c6661c5883bb53d400ce160a5897610ecedbdc9d' eine Zeile, die alle untergeordneten Elemente dieses Commits enthält, vermutlich, ob ein Zweig vorhanden ist oder nicht.

2
user339589

Ich habe das nächste Kind auf folgende Weise gefunden:

git log --reverse --children -n1 HEAD (where 'n' is the number of children to show)
2
DevRQ

Dieser Beitrag ( http://www.jayway.com/2015/03/30/ using-git-commits-to-drive-a-live-coding-session/#comment-282667 ) zeigt einen ordentlichen Weg Wenn dies der Fall ist, können Sie am Ende Ihres Commit-Stacks ein genau definiertes Tag erstellen. Im Wesentlichen git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`' , wobei "demo-end" das letzte Tag ist. 

0
Alex Dresko

Jedes Commit speichert einen Zeiger auf das übergeordnete Element (Parents, im Falle einer Zusammenführung (Standard)).

Es gibt also keine Möglichkeit, auf ein untergeordnetes Commit (falls vorhanden) vom übergeordneten Element zu verweisen.

0
Lakshman Prasad