2009-11-19 3 views
30

Wenn Sie die HEAD an der Mutter der aktuellen HEAD bewegen wollen, ist das einfach:Referenzierung das Kind von einem Commit in Git

git reset --hard HEAD^ 

Aber gibt es eine einfache Möglichkeit, das genaue Gegenteil dieser Operation zu tun das heißt, den Kopf auf den ersten Kind-Commit des aktuellen Kopfs setzen?

Im Moment benutze ich gitk als Workaround (Alt-Tab, Pfeil nach oben, Alt-Tab, Mittelklick), aber ich hätte gerne eine elegantere Lösung, die auch benutzt werden kann, wenn gitk nicht ist verfügbar.

+0

Siehe auch Skript/Befehl ['git children-of'] (http://stackoverflow.com/a/20141722/6309)! – VonC

+0

Es gibt eine gute Lösung bei http://stackoverflow.com/questions/2263674/how-do-i-find-the-next-commit-in-git –

Antwort

16

Sehr wahrscheinlich nicht die schnellstmögliche Lösung, aber es tut, was ich brauche:

 
#!/bin/bash 

REV=$1 

if [ x$REV == x ]; then 
    echo "Usage: git-get-child []" 
    exit 
fi 

HASH=$(git-rev-parse $REV) 

NUM=$2 

if [ x$NUM == x ]; then 
    NUM=1 
fi 

git rev-list --all --parents | grep " $HASH" | sed -n "${NUM}s/\([^ ]*\) .*$/\\1/p" 

Die git rev-list --all --parents genau das tut, was ich brauche: es iteriert alle erreichbaren Commits und druckt die folgende Zeile für jeden:

SHA1_commit SHA1_parent1 SHA1_parent2 usw.

der Raum, in dem grep Ausdruck stellt sicher, dass nur die Zeilen zu finden sind, wo die SHA1 in Frage ein Elternteil ist. Dann bekommen wir die n-te Zeile für das n-te Kind und bekommen die SHA1 des Kindes.

+0

Ich glaube, es sollte 'git rev-list --all sein - Eltern | grep -m 1 -B $ (($ NUM-1)) "$ HASH" | Kopf -1 | sed 's /. * //' 'sonst funktioniert es nicht ganz, wenn $ NUM! = 1 – Schwern

+2

Siehe unten für eine möglicherweise signifikante [Leistungsverbesserung] (http://stackoverflow.com/questions/1761825/referencing-the -child-of-a-commit-in-git/5353204 # 5353204) – MatrixFrog

+0

Beachten Sie, dass dies * nicht * baumelnde Commits findet, dh Commits nicht mehr von jedem Zweig aus erreichbar sind. 'git reset --hard HEAD ^' macht das HEAD-Commit normalerweise unzugänglich (es sei denn, es befindet sich auch in einem Zweig). Das kann nicht alle Commits finden. Um alle Commits zu finden, müssen 'git rev-list --walk-reflog' und/oder' git fsck - unreachable' verwendet werden. – sleske

3

Sie können gitk ... verwenden, da es mehr als ein Kind gibt, gibt es wahrscheinlich keinen einfachen Weg wie .

Wenn Sie Ihre gesamte Operation rückgängig machen möchten, können Sie auch den Reflog verwenden. Verwenden Sie git reflog, um den Zeiger Ihres Commits zu finden, den Sie für den Befehl reset verwenden können. Siehe here.

0

Es ist streng genommen nicht möglich, eine gute Antwort zu geben - da Git verteilt wird, befinden sich die meisten Kinder des Commits, über das Sie nachfragen, möglicherweise in Repositories, die Sie nicht auf Ihrem lokalen Rechner haben! Das ist natürlich eine dumme Antwort, aber etwas zum Nachdenken. Git implementiert selten Operationen, die nicht korrekt implementiert werden können.

+11

Natürlich brauche ich nur die Kinder aus dem aktuellen Repository. – AttishOculus

2

Es hängt davon ab, was Sie fragen. Es könnte eine unendliche Anzahl von Kindern des aktuellen Kopfes in einer unendlichen Anzahl von Zweigen geben, von denen einige lokal sind, einige entfernt und viele, die entfernt wurden und in Ihrem Repository sind, aber nicht Teil einer Geschichte, die Sie veröffentlichen wollen.

Für einen einfachen Fall, wenn Sie gerade einen Reset auf durchgeführt haben, können Sie das Kind, das Sie gerade weggeworfen haben, als [email protected]{1} zurückgeben.

12

Die obige Methode, die git rev-list --all verwendet, berücksichtigt alle verfügbaren Commits, die eine Menge sein können und oft nicht notwendig sind. Wenn die interessante Kind Festschreibungen von einige Zweig erreichbar sind, verpflichtet sich die Zahl der, dass ein Skript interessiert sich für Kind Bedürfnisse Prozess verpflichtet reduziert werden kann:

branches=$(git branch --contains $commit) 

wird die Menge der Zweige bestimmen, die $ begehen ist ein Vorfahre von.

Mit diesem Set sollte git rev-list --parents ^$commit $branches genau die Menge aller Eltern-Kind-Beziehungen zwischen $ commit und allen Zweigstellen, von denen es ein Vorfahr ist, ergeben.

+0

Dies funktionierte für mich, allerdings musste ich die Zeile '* (kein Zweig)' herausfiltern, da ich mich zu diesem Zeitpunkt auf einem Zweig befand. Für mein Repository war das ungefähr 10-mal so schnell, 0,13 s gegenüber 1,4 Sekunden. –

2

Basierend auf der Antwort in How do I find the next commit in git?, habe ich eine andere Lösung, die für mich funktioniert.

Unter der Annahme, dass Sie die nächste Revision auf dem „Master“ Zweig finden wollen, dann können Sie tun:

git log --reverse ${commit}..master | sed 's/commit //; q' 

Dies geht auch davon aus, dass es eine nächste Revision ist, aber das ist eine Art angenommen bei der Frage sowieso.

1

Sie können den Kern des Schöpfers für Hudson (jetzt Jenkins) Kohsuke Kawaguchi (November 2013) verwenden:
kohsuke/git-children-of:

ein begehen, finden sofort Kinder, dass begehen gegeben.

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

Legen Sie das Skript in einem Ordner von Ihrem $PATH Bezug genommen wird, und geben Sie einfach ein:

git children-of <a-commit> 
4

zum Teil auf Paul Wagland's answer und teilweise auf his source, ich bin using the following:

git log --ancestry-path --format=%H ${commit}..master | tail -1 

Ich fand, dass Pauls Antwort mir die falsche Ausgabe für ältere Commits gab (möglicherweise aufgrund der Verschmelzung?), wo der primäre Unterschied ist die --ancestry-path Flagge.

+0

Verwenden Sie '- reverse' und verwenden Sie' head -1' für eine milde Beschleunigung –

+0

Siehe [meine Antwort] (http://stackoverflow.com/a/39558576/5353461) für eine allgemeinere Lösung –

3

Um nur HEAD bewegen (wie gefragt - das den Index oder Arbeits Baum nicht aktualisiert), Verwendung:

git reset --soft $(git child)

Sie werden im Folgenden die Konfiguration aufgelistet verwenden müssen.

Erklärung

Basierend auf @Michael's answer, gehackt ich den child alias in meinem .gitconfig auf.

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

Voreingestellt das Kind des Kopfes, zu geben (es sei denn, eine andere Commit-isch Argument angegeben wird), indem die Vorfahren einen Schritt in Richtung auf die Spitze des Stromzweig folgenden (es sei denn, eine andere Commit-isch als zweites Argument angegeben wird) .

Verwenden Sie %h anstelle von %H, wenn Sie die kurze Hash-Form möchten.

Mit einem frei stehenden Kopf gibt es keinen Zweig, aber das erste Kind bekommen kann immer noch mit diesem Alias ​​erreicht werden:

# 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 der $1 zu $* drucken alle Kinder

+0

Danke - I habe es behoben. –