Ich habe ein Repository mit Filialmaster und A und viele Zusammenführungsaktivitäten zwischen den beiden. Wie kann ich das Commit in meinem Repository finden, wenn Zweig A basierend auf dem Master erstellt wurde?
Mein Repository sieht im Grunde so aus:
-- X -- A -- B -- C -- D -- F (master)
\ / \ /
\ / \ /
G -- H -- I -- J (branch A)
Ich suche nach Revision A, die ich nicht git merge-base (--all)
finde.
Antworten:
Ich habe nach dem gleichen gesucht und diese Frage gefunden. Danke, dass du es gefragt hast!
Ich habe jedoch festgestellt, dass die Antworten, die ich hier sehe, nicht ganz die Antwort zu geben scheinen, nach der Sie gefragt haben (oder nach der ich gesucht habe) - sie scheinen das
G
Commit anstelle desA
Commits zu geben.Also habe ich den folgenden Baum erstellt (Buchstaben in chronologischer Reihenfolge zugewiesen), damit ich die Dinge testen kann:
Das sieht ein bisschen anders aus als deins, weil ich sicherstellen wollte, dass ich (bezogen auf dieses Diagramm, nicht deins) B, aber nicht A (und nicht D oder E) habe. Hier sind die Buchstaben, die an SHA-Präfixe und Commit-Nachrichten angehängt sind (mein Repo kann von hier aus geklont werden , wenn dies für jemanden interessant ist):
So ist das Ziel: Finden Sie B . Hier sind drei Möglichkeiten, die ich nach einigem Basteln gefunden habe:
1. visuell mit gitk:
Sie sollten einen Baum wie diesen visuell sehen (vom Master aus gesehen):
oder hier (vom Thema aus gesehen):
In beiden Fällen habe ich das Commit
B
in meinem Diagramm ausgewählt. Sobald Sie darauf klicken, wird die vollständige SHA in einem Texteingabefeld direkt unter dem Diagramm angezeigt.2. visuell, aber vom Terminal aus:
git log --graph --oneline --all
(Bearbeiten / Randnotiz: Hinzufügen
--decorate
kann auch interessant sein; es fügt eine Angabe von Zweignamen, Tags usw. hinzu. Dies wird nicht zur obigen Befehlszeile hinzugefügt, da die Ausgabe unten nicht die Verwendung widerspiegelt.)was zeigt (vorausgesetzt
git config --global color.ui auto
):Oder im geraden Text:
In beiden Fällen sehen wir das 6aafd7f-Commit als den niedrigsten gemeinsamen Punkt, dh
B
in meinem Diagramm oderA
in Ihrem.3. Mit Muschelmagie:
Sie geben in Ihrer Frage nicht an, ob Sie etwas wie das oben Genannte oder einen einzelnen Befehl wünschen, mit dem Sie nur die eine Revision erhalten, und sonst nichts. Nun, hier ist letzteres:
Was Sie auch in Ihre ~ / .gitconfig einfügen können als (Hinweis: Der nachgestellte Bindestrich ist wichtig; danke Brian, dass er darauf aufmerksam gemacht hat) :
Dies kann über die folgende (mit Anführungszeichen verwickelte) Befehlszeile erfolgen:
Hinweis:
zsh
könnte genauso gut gewesen seinbash
, abersh
wird nicht Arbeit - die<()
Syntax existiert nicht in Vanillesh
. (Nochmals vielen Dank, @conny, dass Sie mich in einem Kommentar zu einer anderen Antwort auf dieser Seite darauf aufmerksam gemacht haben!)Hinweis: Alternative Version der oben genannten:
Vielen Dank an liori für den Hinweis, dass das oben Gesagte beim Vergleich identischer Zweige herunterfallen könnte und eine alternative Diff-Form gefunden wird, die die sed-Form aus der Mischung entfernt und diese "sicherer" macht (dh ein Ergebnis zurückgibt (nämlich die letztes Commit), auch wenn Sie Master mit Master vergleichen):
Als .git-config-Zeile:
Aus der Schale:
In meinem Testbaum (der für eine Weile nicht verfügbar war, tut mir leid; er ist zurück) funktioniert dies nun sowohl für den Master als auch für das Thema (Festschreiben von G bzw. B). Nochmals vielen Dank, Liori, für die alternative Form.
Das habe ich mir [und Liori] ausgedacht. Es scheint für mich zu funktionieren. Es erlaubt auch ein paar zusätzliche Aliase, die sich als nützlich erweisen könnten:
Viel Spaß beim Spielen!
quelle
diff
den Wenn-Dann-Sonst-Modus zu verwenden und geänderte / gelöschte Zeilen aus der Ausgabe zu löschen, anstatt auf einen ausreichend großen Kontext zu zählendiff --old-line-format='' --new-line-format='' <(git rev-list …) <(git rev-list …)|head -1
.git log -n1 --format=format:%H $(git log --reverse --format=format:%H master..topic | head -1)~
wird auch funktionieren, denke ichgit merge-base --fork-point ...
, Commit B (Commit6aafd7f
) für diesen Baum zu geben? Ich war mit anderen Dingen beschäftigt, als du das gepostet hast, und es klang gut, aber ich habe es endlich versucht, und ich bringe es nicht zum Laufen ... Ich bekomme entweder etwas Neueres oder nur einen stillen Fehler (kein Fehler) Nachricht, aber Exit - Status 1), Argumente wie der Versuchgit co master; git merge-base --fork-point topic
,git co topic; git merge-base --fork-point master
,git merge-base --fork-point topic master
(für beide Kasse) usw. gibt es etwas , was ich falsch mache oder fehlt?--fork-point
basiert auf dem Reflog, daher funktioniert es nur, wenn Sie die Änderungen lokal vorgenommen haben. Selbst dann könnten die Reflog-Einträge abgelaufen sein. Es ist nützlich, aber überhaupt nicht zuverlässig.Sie suchen vielleicht
git merge-base
:quelle
--all
Option zu "git merge-base
"git merge-base
fünf Stunden nach dem Posten meiner Antwort enthält (wahrscheinlich als Antwort auf meine Antwort). Trotzdem werde ich diese Antwort unverändert lassen, da sie für andere Personen, die diese Frage über die Suche finden, möglicherweise noch nützlich ist.Ich habe
git rev-list
für so etwas verwendet. Zum Beispiel (beachten Sie die 3 Punkte)wird den Verzweigungspunkt ausspucken. Jetzt ist es nicht perfekt; Da Sie Master ein paar Mal in Zweig A zusammengeführt haben, werden einige mögliche Verzweigungspunkte aufgeteilt (im Grunde der ursprüngliche Verzweigungspunkt und dann jeder Punkt, an dem Sie Master in Zweig A zusammengeführt haben). Es sollte jedoch zumindest die Möglichkeiten einschränken.
Ich habe diesen Befehl zu meinen Aliasnamen hinzugefügt
~/.gitconfig
als:so kann ich es nennen als:
quelle
G
stattA
, gemäß der Grafik in der ursprünglichen Frage.) Ich habe eine Antwort, die bekommtA
, dass ich gleich posten werde.git checkout topic
und das Sie danntopic
anstelle von ausführen könnenbranch-a
) werden648ca357b946939654da12aaf2dc072763f3caee
und37ad15952db5c065679d7fc31838369712f0b338
- beide aufgelistet37ad159
und648ca35
befinden sich im Vorfahren der aktuellen Zweige (letzterer ist der aktuelle HEAD vontopic
). aber es ist auch nicht der Punkt vor der Verzweigung. Bekommst du etwas anderesWenn Sie knappe Befehle mögen,
Hier ist eine Erklärung.
Mit dem folgenden Befehl erhalten Sie eine Liste aller Commits im Master, die nach dem Erstellen von branch_name aufgetreten sind
Da Sie sich nur um die frühesten dieser Commits kümmern, möchten Sie die letzte Zeile der Ausgabe:
Das übergeordnete Element des frühesten Commits, das kein Vorfahr von "branch_name" ist, befindet sich per Definition in "branch_name" und in "master", da es ein Vorfahr von etwas in "master" ist. Sie haben also das früheste Commit in beiden Branchen.
Der Befehl
ist nur eine Möglichkeit, die übergeordnete Commit-Referenz anzuzeigen. Du könntest benutzen
oder Wasauchimmer.
PS: Ich bin mit dem Argument nicht einverstanden, dass die Reihenfolge der Vorfahren irrelevant ist. Es kommt darauf an, was Sie wollen. Zum Beispiel in diesem Fall
Es ist absolut sinnvoll, C2 als "Verzweigungs" -Commit auszugeben. Dies ist der Zeitpunkt, an dem der Entwickler von "master" abzweigte. Als er verzweigte, wurde Zweig "B" nicht einmal in seinem Zweig zusammengeführt! Dies ist, was die Lösung in diesem Beitrag gibt.
Wenn Sie das letzte Commit C wünschen, sodass alle Pfade vom Ursprung bis zum letzten Commit in Zweig "A" durch C verlaufen, möchten Sie die Reihenfolge der Vorfahren ignorieren. Das ist rein topologisch und gibt Ihnen eine Vorstellung davon, wann zwei Versionen des Codes gleichzeitig ausgeführt werden. Dann würden Sie sich für merge-basierte Ansätze entscheiden, und in meinem Beispiel wird C1 zurückgegeben.
quelle
git rev-list commit^^!
kann vereinfacht werden alsgit rev-parse commit^
git rev-list --first-parent ^branch_name master
mit ,git rev-list --first-parent branch_name ^master
denn wenn der Meister Zweig 0 Commits vor dem anderen Zweig (schnell weiterleitbares es), so würde kein Ausgang erzeugt werden. Mit meiner Lösung wird keine Ausgabe erstellt, wenn der Master streng voraus ist (dh der Zweig wurde vollständig zusammengeführt), was ich möchte.git rev-list --first-parent ^topic master
bringt Sie erst nach dem letzten Zusammenführen vonmaster
in zum ersten Commit zurücktopic
(falls das überhaupt existiert).Da so viele der Antworten in diesem Thread nicht die Antwort geben, nach der die Frage gefragt wurde, finden Sie hier eine Zusammenfassung der Ergebnisse jeder Lösung sowie das Skript, mit dem ich das in der Frage angegebene Repository repliziert habe.
Das Protokoll
Wenn wir ein Repository mit der angegebenen Struktur erstellen, erhalten wir das Git-Protokoll von:
Meine einzige Ergänzung ist das Tag, das explizit den Punkt angibt, an dem wir den Zweig erstellt haben, und damit das Commit, das wir finden möchten.
Die Lösung, die funktioniert
Die einzige Lösung, die funktioniert, ist die von lindes bereitgestellte, die korrekt zurückgibt
A
:Wie Charles Bailey jedoch betont, ist diese Lösung sehr spröde.
Wenn Sie
branch_A
inmaster
und dann verschmelzenmaster
inbranch_A
ohne Lösung Commits dann Lindes' dazwischen gibt Ihnen nur die neueste zuerst divergance .Das bedeutet, dass ich mich für meinen Workflow an das Markieren des Verzweigungspunkts lang laufender Zweige halten muss, da ich nicht garantieren kann, dass sie später zuverlässig gefunden werden können.
Das alles läuft darauf hinaus, dass es an dem
git
mangelt, was benannte Zweigehg
nennt . Der Blogger jhw nennt diese Abstammungslinien vs. Familien in seinem Artikel Warum ich Mercurial mehr als Git mag und seinem Folgeartikel More On Mercurial vs. Git (mit Grafiken!) . Ich würde den Leuten empfehlen, sie zu lesen, um zu sehen, warum einige Quecksilberkonvertierte es vermissen, keine Zweige benannt zu habengit
.Die Lösungen, die nicht funktionieren
Die Lösung von mipadi gibt zwei Antworten,
I
undC
:Die von Greg Hewgill bereitgestellte Lösung kehrt zurück
I
Die von Karl bereitgestellte Lösung kehrt zurück
X
:Das Skript
Ich bezweifle, dass die Git-Version einen großen Unterschied macht, aber:
Vielen Dank an Charles Bailey , der mir eine kompaktere Möglichkeit gezeigt hat, das Beispiel-Repository zu skripten.
quelle
diff -u <(git rev-list branch_A) <(git rev-list master) | tail -2 | head -1
. Vielen Dank für die Bereitstellung von Anweisungen zum Erstellen desDies ist im Allgemeinen nicht möglich. In einer Zweighistorie wurde ein Zweig-und-Zusammenführen vor dem Verzweigen eines benannten Zweigs und ein Zwischenzweig von zwei benannten Zweigen gleich aussehen.
In git sind Zweige nur die aktuellen Namen der Spitzen von Abschnitten der Geschichte. Sie haben nicht wirklich eine starke Identität.
Dies ist normalerweise kein großes Problem, da die Zusammenführungsbasis (siehe Greg Hewgills Antwort) von zwei Commits normalerweise viel nützlicher ist und das letzte Commit ergibt, das die beiden Zweige gemeinsam genutzt haben.
Eine Lösung, die sich auf die Reihenfolge der Eltern eines Commits stützt, funktioniert offensichtlich nicht in Situationen, in denen ein Zweig zu einem bestimmten Zeitpunkt in der Geschichte des Zweigs vollständig integriert wurde.
Diese Technik fällt auch dann aus, wenn eine Integrationszusammenführung mit den Eltern in umgekehrter Reihenfolge durchgeführt wurde (z. B. wurde ein temporärer Zweig verwendet, um eine Testzusammenführung in den Master durchzuführen, und dann in den Feature-Zweig vorgespult, um weiter darauf aufzubauen).
quelle
git
hätte ein Äquivalent zuhg
den genannten Filialen, was die Verwaltung langlebiger Wartungsfilialen so viel einfacher machen würde.Wie wäre es mit so etwas
quelle
diverges = !bash -c 'git rev-parse $(diff <(git log --pretty=oneline ${1}) <(git log --pretty=oneline ${2}) | tail -1 | cut -c 3-42)^'
(ohne temporäre Dateien)G
stattA
gemäß der Grafik in der ursprünglichen Frage.) Ich denke, ich habe jedoch eine Antwort gefunden, die ich gleich veröffentlichen werde.diff -u <(git rev-list branch_A) <(git rev-list master) | tail -2 | head -1
Sicherlich fehlt mir etwas, aber IMO, alle oben genannten Probleme werden verursacht, weil wir immer versuchen, den Verzweigungspunkt zu finden, der in den Verlauf zurückgeht, und das verursacht aufgrund der verfügbaren Zusammenführungskombinationen alle möglichen Probleme.
Stattdessen habe ich einen anderen Ansatz gewählt, der auf der Tatsache basiert, dass beide Zweige viel Geschichte gemeinsam haben. Genau die gesamte Geschichte vor der Verzweigung ist zu 100% gleich. Statt zurückzugehen, geht es in meinem Vorschlag darum, vorwärts zu gehen (ab dem 1.) begehen) und suchen nach dem 1. Unterschied in beiden Zweigen. Der Verzweigungspunkt ist einfach das übergeordnete Element des ersten gefundenen Unterschieds.
In der Praxis:
Und es löst alle meine üblichen Fälle. Sicher gibt es Grenzabdeckungen, die nicht abgedeckt sind, aber ... ciao :-)
quelle
comm --nocheck-order -1 -2 <(git rev-list --reverse --topo-order topic) <(git rev-list --reverse --topo-order master) | head -1
Ich musste kürzlich auch dieses Problem lösen und schrieb schließlich ein Ruby-Skript dafür: https://github.com/vaneyckt/git-find-branching-point
quelle
Nach vielen Recherchen und Diskussionen ist klar, dass es kein Wundermittel gibt, das in allen Situationen funktionieren würde, zumindest nicht in der aktuellen Version von Git.
Deshalb habe ich ein paar Patches geschrieben, die das Konzept eines
tail
Zweigs hinzufügen . Jedes Mal, wenn ein Zweig erstellt wird, wird auch ein Zeiger auf den ursprünglichen Punkt erstellt, dietail
Referenz. Diese Referenz wird jedes Mal aktualisiert, wenn der Zweig neu basiert.Um den Verzweigungspunkt des Entwicklungszweigs herauszufinden, müssen Sie nur verwenden
devel@{tail}
, das war's.https://github.com/felipec/git/commits/fc/tail
quelle
Hier ist eine verbesserte Version meiner vorherigen Antwort . Es stützt sich auf die Festschreibungsnachrichten aus Zusammenführungen, um herauszufinden, wo der Zweig zuerst erstellt wurde.
Es funktioniert auf allen hier erwähnten Repositories, und ich habe sogar einige knifflige angesprochen, die auf der Mailingliste aufgetaucht sind . Ich habe auch Tests dafür geschrieben.
quelle
Der folgende Befehl zeigt den SHA1 von Commit A.
git merge-base --fork-point A
quelle
Ich scheine etwas Freude damit zu haben
Die letzte Zeile, die Sie erhalten, ist das erste Commit für den Zweig. Dann geht es darum, das übergeordnete Element zu ermitteln. Damit
Scheint für mich zu funktionieren und benötigt keine Unterschiede usw. (was hilfreich ist, da wir diese Version von diff nicht haben)
Korrektur: Dies funktioniert nicht, wenn Sie sich im Hauptzweig befinden, aber ich mache dies in einem Skript, sodass dies weniger problematisch ist
quelle
Sie können dies verwenden, um Commits vom Verzweigungspunkt aus zu finden.
quelle
Manchmal ist es effektiv unmöglich (mit einigen Ausnahmen, wo Sie möglicherweise Glück haben, zusätzliche Daten zu haben) und die Lösungen hier funktionieren nicht.
Git bewahrt den Ref-Verlauf (einschließlich Zweige) nicht auf. Es wird nur die aktuelle Position für jeden Zweig (den Kopf) gespeichert. Dies bedeutet, dass Sie mit der Zeit einige Zweigverläufe in Git verlieren können. Wenn Sie beispielsweise verzweigen, geht sofort verloren, welcher Zweig der ursprüngliche war. Alles, was ein Zweig tut, ist:
Sie können davon ausgehen, dass der erste Commit der Zweig ist. Dies ist in der Regel der Fall, aber nicht immer so. Nichts hindert Sie daran, sich nach dem obigen Vorgang zuerst in einen Zweig zu begeben. Außerdem ist nicht garantiert, dass Git-Zeitstempel zuverlässig sind. Erst wenn Sie sich zu beiden verpflichten, werden sie strukturell zu echten Zweigen.
Während wir in Diagrammen dazu neigen, Commits konzeptionell zu nummerieren, hat git kein wirklich stabiles Konzept der Sequenz, wenn sich der Commit-Baum verzweigt. In diesem Fall können Sie davon ausgehen, dass die Zahlen (die die Reihenfolge angeben) durch den Zeitstempel bestimmt werden (es kann Spaß machen zu sehen, wie eine Git-Benutzeroberfläche mit Dingen umgeht, wenn Sie alle Zeitstempel auf denselben Wert setzen).
Das erwartet ein Mensch konzeptionell:
Das bekommen Sie tatsächlich:
Sie würden annehmen, dass B1 der ursprüngliche Zweig ist, aber es könnte sich einfach um einen toten Zweig handeln (jemand hat -b ausgecheckt, aber nie dazu verpflichtet). Erst wenn Sie sich zu beiden verpflichten, erhalten Sie eine legitime Zweigstruktur innerhalb von git:
Sie wissen immer, dass C1 vor C2 und C3 kam, aber Sie wissen nie zuverlässig, ob C2 vor C3 oder C3 vor C2 kam (weil Sie die Zeit auf Ihrer Workstation beispielsweise auf irgendetwas einstellen können). B1 und B2 sind ebenfalls irreführend, da Sie nicht wissen können, welcher Zweig zuerst kam. In vielen Fällen können Sie eine sehr gute und normalerweise genaue Vermutung anstellen. Es ist ein bisschen wie eine Rennstrecke. Wenn alle Dinge im Allgemeinen mit den Autos gleich sind, können Sie davon ausgehen, dass ein Auto, das in einer Runde dahinter kommt, eine Runde dahinter gestartet ist. Wir haben auch Konventionen, die sehr zuverlässig sind, zum Beispiel wird der Meister fast immer die langlebigsten Zweige darstellen, obwohl ich leider Fälle gesehen habe, in denen selbst dies nicht der Fall ist.
Das hier gegebene Beispiel ist ein geschichtserhaltendes Beispiel:
Real hier ist auch irreführend, weil wir als Menschen es von links nach rechts lesen, Wurzel zu Blatt (ref). Git macht das nicht. Wo wir (A-> B) in unseren Köpfen tun, tut Git (A <-B oder B-> A). Es liest es von ref bis root. Refs können überall sein, sind aber eher Blätter, zumindest für aktive Zweige. Ein Ref verweist auf ein Commit und Commits enthalten nur ein Like für ihre Eltern, nicht für ihre Kinder. Wenn es sich bei einem Commit um ein Merge-Commit handelt, hat es mehr als ein übergeordnetes Element. Das erste übergeordnete Element ist immer das ursprüngliche Commit, mit dem es zusammengeführt wurde. Die anderen Eltern sind immer Commits, die mit dem ursprünglichen Commit zusammengeführt wurden.
Dies ist keine sehr effiziente Darstellung, sondern ein Ausdruck aller Pfade, die git von jeder Referenz (B1 und B2) nehmen kann.
Der interne Speicher von Git sieht eher so aus (nicht, dass A als übergeordnetes Element zweimal vorkommt):
Wenn Sie ein Raw-Git-Commit ausgeben, werden null oder mehr übergeordnete Felder angezeigt. Wenn es Null gibt, bedeutet dies, dass kein übergeordnetes Element vorhanden ist und das Commit eine Wurzel ist (Sie können tatsächlich mehrere Wurzeln haben). Wenn es eine gibt, bedeutet dies, dass keine Zusammenführung stattgefunden hat und es sich nicht um ein Root-Commit handelt. Wenn es mehr als eine gibt, bedeutet dies, dass das Commit das Ergebnis einer Zusammenführung ist und alle Eltern nach der ersten Zusammenführung Commits sind.
Wenn beide A treffen, ist ihre Kette dieselbe, davor ist ihre Kette völlig unterschiedlich. Das erste Commit, das zwei weitere Commits gemeinsam haben, ist der gemeinsame Vorfahr, von dem sie abweichen. Hier kann es zu Verwechslungen zwischen den Begriffen commit, branch und ref kommen. Sie können tatsächlich ein Commit zusammenführen. Das macht Merge wirklich. Ein Ref zeigt einfach auf ein Commit und ein Zweig ist nichts anderes als ein Ref im Ordner .git / refs / Heads. Der Ordnerspeicherort bestimmt, dass ein Ref ein Zweig ist und nicht etwas anderes wie ein Tag.
Wenn Sie die Geschichte verlieren, führt die Zusammenführung je nach den Umständen eines von zwei Dingen aus.
Erwägen:
In diesem Fall wird durch eine Zusammenführung in beide Richtungen ein neues Commit erstellt, wobei das erste übergeordnete Element das Commit ist, auf das der aktuell ausgecheckte Zweig zeigt, und das zweite übergeordnete Element als Commit an der Spitze des Zweigs, den Sie mit Ihrem aktuellen Zweig zusammengeführt haben. Es muss ein neues Commit erstellt werden, da beide Zweige seit ihrem gemeinsamen Vorfahren Änderungen aufweisen, die kombiniert werden müssen.
Zu diesem Zeitpunkt hat D (B1) nun beide Änderungssätze von beiden Zweigen (selbst und B2). Der zweite Zweig hat jedoch nicht die Änderungen von B1. Wenn Sie die Änderungen von B1 in B2 zusammenführen, damit sie synchronisiert werden, können Sie etwas erwarten, das so aussieht (Sie können git merge dazu zwingen, dies jedoch mit --no-ff zu tun):
Sie erhalten dies auch dann, wenn B1 zusätzliche Commits hat. Solange es in B2 keine Änderungen gibt, die B1 nicht hat, werden die beiden Zweige zusammengeführt. Es führt einen schnellen Vorlauf durch, der einer Rebase ähnelt (Rebases fressen oder linearisieren den Verlauf), außer dass im Gegensatz zu einer Rebase, da nur ein Zweig einen Änderungssatz hat, kein Änderungssatz von einem Zweig auf den anderen angewendet werden muss.
Wenn Sie die Arbeit an B1 einstellen, sind die Dinge weitgehend in Ordnung, um die Geschichte langfristig zu bewahren. Nur B1 (möglicherweise Master) wird in der Regel weiterentwickelt, sodass die Position von B2 in der B2-Historie erfolgreich den Punkt darstellt, an dem es in B1 zusammengeführt wurde. Dies ist, was Git von Ihnen erwartet, um B von A zu verzweigen. Dann können Sie A nach Belieben mit B zusammenführen, wenn sich Änderungen ansammeln. Wenn Sie jedoch B wieder mit A zusammenführen, wird nicht erwartet, dass Sie an B und weiter arbeiten . Wenn Sie nach dem schnellen Vorlauf weiter an Ihrem Zweig arbeiten und ihn wieder mit dem Zweig zusammenführen, an dem Sie gearbeitet haben, löschen Sie jedes Mal den vorherigen Verlauf von B. Sie erstellen wirklich jedes Mal einen neuen Zweig, nachdem Sie die Quelle schnell vorgespult und dann den Zweig festgeschrieben haben.
1 bis 3 und 5 bis 8 sind strukturelle Zweige, die angezeigt werden, wenn Sie dem Verlauf für 4 oder 9 folgen. Es gibt keine Möglichkeit in git zu wissen, zu welchen dieser unbenannten und nicht referenzierten strukturellen Zweige mit den genannten und Referenzzweigen als die gehören Ende der Struktur. Sie könnten aus dieser Zeichnung annehmen, dass 0 bis 4 zu B1 und 4 bis 9 zu B2 gehören, aber abgesehen von 4 und 9 konnte nicht wissen, welcher Zweig zu welchem Zweig gehört, ich habe es einfach so gezeichnet, dass das ergibt Illusion davon. 0 könnte zu B2 gehören und 5 könnte zu B1 gehören. In diesem Fall gibt es 16 verschiedene Möglichkeiten, zu welchem benannten Zweig jeder der strukturellen Zweige gehören könnte.
Es gibt eine Reihe von Git-Strategien, die dies umgehen. Sie können das Zusammenführen von Git erzwingen, um niemals schnell vorzuspulen und immer einen Zusammenführungszweig zu erstellen. Eine schreckliche Möglichkeit, den Zweigverlauf beizubehalten, besteht darin, Tags und / oder Zweige (Tags werden wirklich empfohlen) gemäß einer Konvention Ihrer Wahl zu verwenden. Ich würde wirklich keinen leeren Dummy-Commit in dem Zweig empfehlen, in den Sie zusammenführen. Eine sehr verbreitete Konvention besteht darin, erst dann in einen Integrationszweig zu verschmelzen, wenn Sie Ihren Zweig wirklich schließen möchten. Dies ist eine Praxis, an die sich die Leute halten sollten, da Sie sonst daran arbeiten, Zweige zu haben. In der realen Welt ist das Ideal jedoch nicht immer praktisch, was bedeutet, dass es nicht in jeder Situation möglich ist, das Richtige zu tun. Wenn was du '
quelle
man git-reflog
und den Teil über Daten: "master@{one.week.ago} bedeutet" wo der Master vor einer Woche in diesem lokalen Repository darauf hingewiesen hat "". Oder die Diskussion am<refname>@{<date>}
inman gitrevisions
. Undcore.reflogExpire
inman git-config
.Keine Lösung für die Frage, aber ich dachte, es lohnt sich, den Ansatz zu erwähnen, den ich verwende, wenn ich einen langlebigen Zweig habe:
Während ich den Zweig erstelle, erstelle ich auch ein Tag mit demselben Namen, aber mit einem
-init
Suffix, zum Beispielfeature-branch
undfeature-branch-init
.(Es ist irgendwie bizarr, dass diese Frage so schwer zu beantworten ist!)
quelle
Eine einfache Möglichkeit, das Erkennen des Verzweigungspunkts zu vereinfachen,
git log --graph
ist die Verwendung der Option--first-parent
.Nehmen Sie zum Beispiel das Repo aus der akzeptierten Antwort :
Fügen Sie nun hinzu
--first-parent
:Das macht es einfacher!
Beachten Sie, dass Sie, wenn das Repo viele Zweige hat, die 2 Zweige angeben möchten, die Sie vergleichen, anstatt Folgendes zu verwenden
--all
:quelle
Das Problem scheint darin zu bestehen, den jüngsten Single-Commit- Schnitt zwischen beiden Zweigen auf der einen Seite und dem frühesten gemeinsamen Vorfahren auf der anderen Seite zu finden (wahrscheinlich das anfängliche Commit des Repos). Dies entspricht meiner Intuition, was der "Verzweigungspunkt" ist.
Vor diesem Hintergrund ist dies mit normalen Git-Shell-Befehlen überhaupt nicht einfach zu berechnen, da
git rev-list
wir - unser leistungsstärkstes Tool - den Pfad, über den ein Commit erreicht wird, nicht einschränken können . Das nächste, das wir haben, ist dasgit rev-list --boundary
, was uns eine Reihe aller Verpflichtungen geben kann, die "unseren Weg blockiert" haben. (Hinweis:git rev-list --ancestry-path
ist interessant, aber ich weiß nicht, wie ich es hier nützlich machen kann.)Hier ist das Skript: https://gist.github.com/abortz/d464c88923c520b79e3d . Es ist relativ einfach, aber aufgrund einer Schleife ist es kompliziert genug, um einen Kern zu rechtfertigen.
Beachten Sie, dass die meisten anderen hier vorgeschlagenen Lösungen aus einem einfachen Grund möglicherweise nicht in allen Situationen funktionieren können: Sie
git rev-list --first-parent
sind bei der Linearisierung des Verlaufs nicht zuverlässig, da bei beiden Ordnungen Zusammenführungen auftreten können.git rev-list --topo-order
Auf der anderen Seite ist es sehr nützlich - für das Gehen von Commits in topografischer Reihenfolge -, aber Unterschiede zu machen ist spröde: Es gibt mehrere mögliche topografische Ordnungen für ein bestimmtes Diagramm, sodass Sie von einer bestimmten Stabilität der Ordnungen abhängig sind. Trotzdem funktioniert die Lösung von strongk7 wahrscheinlich die meiste Zeit verdammt gut. Es ist jedoch langsamer als meine, weil ich die gesamte Geschichte des Repos zweimal durchlaufen muss. :-)quelle
Im Folgenden wird das Git-Äquivalent von svn log --stop-on-copy implementiert und kann auch zum Ermitteln des Verzweigungsursprungs verwendet werden.
Ansatz
Wie alle Flüsse, die zum Meer fließen, laufen alle Zweige, um zu meistern, und daher finden wir eine Verbindungsbasis zwischen scheinbar nicht verwandten Zweigen. Wenn wir vom Astkopf durch die Vorfahren zurückgehen, können wir an der ersten möglichen Zusammenführungsbasis anhalten, da dies theoretisch der Ursprungspunkt dieses Zweigs sein sollte.
Anmerkungen
Details: https://stackoverflow.com/a/35353202/9950
quelle
Mit dem folgenden Befehl können Sie das älteste Commit in branch_a zurückgeben, das vom Master nicht erreichbar ist:
Vielleicht mit einer zusätzlichen Plausibilitätsprüfung , dass die Eltern davon zu begehen ist tatsächlich erreichbar von Master ...
quelle
Sie können das Reflog von Zweig A untersuchen, um herauszufinden, aus welchem Commit er erstellt wurde, sowie den vollständigen Verlauf, auf den Commits in diesem Zweig verwiesen haben. Reflogs sind in
.git/logs
.quelle
Ich glaube, ich habe einen Weg gefunden, der mit allen hier genannten Eckfällen umgeht:
Charles Bailey hat völlig Recht, dass Lösungen, die auf der Reihenfolge der Vorfahren basieren, nur einen begrenzten Wert haben. Am Ende des Tages benötigen Sie eine Art Datensatz "Dieses Commit stammt aus Zweig X", aber ein solcher Datensatz ist bereits vorhanden. Standardmäßig verwendet 'git merge' eine Festschreibungsnachricht wie "Zweig 'branch_A' in master zusammenführen". Dies zeigt an, dass alle Festschreibungen des zweiten übergeordneten Elements (Festschreiben ^ 2) von 'branch_A' stammen und mit dem ersten zusammengeführt wurden parent (commit ^ 1), das ist 'master'.
Mit diesen Informationen können Sie die erste Zusammenführung von 'branch_A' finden (als 'branch_A' wirklich entstand) und die Zusammenführungsbasis finden, die der Verzweigungspunkt wäre :)
Ich habe es mit den Repositories von Mark Booth und Charles Bailey versucht und die Lösung funktioniert. wie konnte es nicht? Dies funktioniert nur, wenn Sie die Standard-Festschreibungsnachricht für Zusammenführungen manuell geändert haben, sodass die Zweiginformationen wirklich verloren gehen.
Für die Nützlichkeit:
Dann kannst du machen '
git branch-point branch_A
' machen.Genießen ;)
quelle
git merge -m
sage häufig , was ich zusammengeführt habe, anstatt den Namen eines potenziell kurzlebigen Zweigs (z. B. "Änderungen der Hauptlinie in Feature-XYZ-Refaktor zusammenführen"). Angenommen, ich wäre-m
in meinem Beispiel weniger hilfreich gewesen ? Das Problem ist in seiner Gesamtheit einfach nicht lösbar, da ich mit einem oder zwei temporären Zweigen dieselbe Geschichte schreiben kann und es keine Möglichkeit gibt, den Unterschied zu erkennen.