592 Stimmen

Einen Verzweigungspunkt mit Git finden?

Ich habe ein Repository mit den Zweigen master und A und viele Merge-Aktivitäten zwischen den beiden. Wie kann ich die Übergabe in meinem Repository finden, wenn Zweig A auf der Grundlage von master erstellt wurde?

Mein Repository sieht im Wesentlichen wie folgt aus:

-- X -- A -- B -- C -- D -- F  (master) 
          \     /   \     /
           \   /     \   /
             G -- H -- I -- J  (branch A)

Ich bin auf der Suche nach Revision A, die nicht das ist, was git merge-base (--all) findet.

13voto

CB Bailey Punkte 693084

Im Allgemeinen ist dies nicht möglich. In einer Verzweigungshistorie sehen eine Verzweigung und eine Zusammenführung, bevor eine benannte Verzweigung abgezweigt wurde, und eine Zwischenverzweigung von zwei benannten Verzweigungen gleich aus.

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 Merge-Base (siehe Greg Hewgills Antwort) von zwei Commits normalerweise viel nützlicher ist, da sie den letzten Commit angibt, den die beiden Zweige gemeinsam haben.

Eine Lösung, die sich auf die Reihenfolge der Eltern eines Commits stützt, funktioniert natürlich nicht in Situationen, in denen ein Zweig zu einem bestimmten Zeitpunkt in der Geschichte des Zweigs vollständig integriert wurde.

git commit --allow-empty -m root # actual branch commit
git checkout -b branch_A
git commit --allow-empty -m  "branch_A commit"
git checkout master
git commit --allow-empty -m "More work on master"
git merge -m "Merge branch_A into master" branch_A # identified as branch point
git checkout branch_A
git merge --ff-only master
git commit --allow-empty -m "More work on branch_A"
git checkout master
git commit --allow-empty -m "More work on master"

Diese Technik versagt auch, wenn eine Integrationszusammenführung mit umgekehrten Eltern durchgeführt wurde (z.B. wurde ein temporärer Zweig verwendet, um eine Testzusammenführung in den Master-Zweig durchzuführen und dann schnell in den Feature-Zweig vorgespult, um darauf weiter aufzubauen).

git commit --allow-empty -m root # actual branch point
git checkout -b branch_A
git commit --allow-empty -m  "branch_A commit"
git checkout master
git commit --allow-empty -m "More work on master"
git merge -m "Merge branch_A into master" branch_A # identified as branch point
git checkout branch_A
git commit --allow-empty -m "More work on branch_A"

git checkout -b tmp-branch master
git merge -m "Merge branch_A into tmp-branch (master copy)" branch_A
git checkout branch_A
git merge --ff-only tmp-branch
git branch -d tmp-branch

git checkout master
git commit --allow-empty -m "More work on master"

10voto

VonC Punkte 1117238

Git 2.36 schlägt einen einfacheren Befehl vor:

git rev-parse $(git rev-list --exclude-first-parent-only A ^master| head -1)^
  • git rev-list --exclude-first-parent-only A ^master gibt Ihnen G -- H -- I -- J
  • head -1 gibt Ihnen G
  • git rev-parse G^ gibt Ihnen sein erstes Elternteil: A

Mit Git 2.36 (Q2 2022), " git log " ( man ) und Freunde lernten eine Option --exclude-first-parent-only um das UNINTERESTING-Bit nur entlang der Kette des ersten Elternteils nach unten zu propagieren, genau wie --first-parent zeigt Commits, denen das UNINTERESTING-Bit fehlt, nur entlang der Kette der ersten Eltern.

Ver Übergabe 9d505b7 (11. Januar 2022) von Jerry Zhang ( jerry-skydio ) .
(Zusammengefasst von Junio C. Hamano -- gitster -- en 708cbef übergeben , 17. Februar 2022)

git-rev-list --exclude-first-parent-only Flag hinzufügen

Abgezeichnet von: Jerry Zhang

Es ist nützlich zu wissen, wann ein Zweig zum ersten Mal in der Geschichte von einem Integrationszweig abgewichen ist, um die lokalen Änderungen des Benutzers aufzählen zu können.
Diese lokalen Änderungen können jedoch beliebige Verschmelzungen beinhalten, so dass diese Verschmelzungsstruktur bei der Ermittlung des Divergenzpunkts ignoriert werden muss.

Um dies zu tun, lehren Sie die " rev-list " Familie zu akzeptieren " --exclude-first-parent-only ", die schränkt die Durchquerung der ausgeschlossenen Commits ein, um nur den ersten übergeordneten Links zu folgen .

-A-----E-F-G--main
  \   / /
   B-C-D--topic

In diesem Beispiel ist das Ziel, die Menge {B, C, D } der einen Themenzweig darstellt, der in main Zweigstelle.
git rev-list topic ^main ( man ) wird am Ende keine Commits zurückgeben, da der Ausschluss von main durchläuft am Ende die Commits auf topic auch.
git rev-list --exclude-first-parent-only topic ^main ( man ) wird jedoch zurückkehren {B, C, D} wie gewünscht.

Hinzufügen von Dokumenten für das neue Flag und Klarstellung des Dokuments für --first-parent um anzugeben, dass sie nur für das Durchlaufen der Menge der eingeschlossenen Commits gilt.

rev-list-options umfasst nun in seinem Manpage :

--first-parent

Bei der Suche nach einzuschließenden Commits folgen Sie nur dem ersten Eltern-Commit, wenn Sie einen Merge-Commit sehen.

Diese Option kann einen besseren Überblick bei der Betrachtung der Entwicklung von eines bestimmten Themenzweigs, da Zusammenführungen in einen Themen Zweig neigen dazu, sich nur an aktualisierte Upstreams anzupassen von Zeit zu Zeit, und diese Option erlaubt Ihnen, die die einzelnen Commits, die durch einen solchen Merge in Ihre Historie einer Zusammenführung.

rev-list-options umfasst nun in seinem Manpage :

--exclude-first-parent-only

Bei der Suche nach auszuschließenden Commits (mit einem '{caret}'), folgen Sie nur dem ersten übergeordneten Commit, wenn Sie einen Merge-Commit sehen.

Dies kann verwendet werden, um die Menge der Änderungen in einem Themenzweig zu finden ab dem Punkt zu finden, an dem er vom entfernten Zweig abgewichen ist, vorausgesetzt dass beliebige Zusammenführungen gültige Themenzweigänderungen sein können.

7voto

binaryfunt Punkte 5570

Ein einfacher Weg, um den Verzweigungspunkt in git log --graph ist die Verwendung der Option --first-parent .

Nehmen Sie zum Beispiel die Repo von der akzeptierte Antwort :

$ git log --all --oneline --decorate --graph

*   a9546a2 (HEAD -> master, origin/master, origin/HEAD) merge from topic back to master
|\  
| *   648ca35 (origin/topic) merging master onto topic
| |\  
| * | 132ee2a first commit on topic branch
* | | e7c863d commit on master after master was merged to topic
| |/  
|/|   
* | 37ad159 post-branch commit on master
|/  
* 6aafd7f second commit on master before branching
* 4112403 initial commit on master

Jetzt hinzufügen --first-parent :

$ git log --all --oneline --decorate --graph --first-parent

* a9546a2 (HEAD -> master, origin/master, origin/HEAD) merge from topic back to master
| * 648ca35 (origin/topic) merging master onto topic
| * 132ee2a first commit on topic branch
* | e7c863d commit on master after master was merged to topic
* | 37ad159 post-branch commit on master
|/  
* 6aafd7f second commit on master before branching
* 4112403 initial commit on master

Das macht es einfacher!

Beachten Sie, wenn das Repo viele Zweige hat, werden Sie die 2 Zweige angeben wollen, die Sie vergleichen wollen, anstatt --all :

$ git log --decorate --oneline --graph --first-parent master origin/topic

7voto

Karl Punkte 678

Wie wäre es mit etwas wie

git log --pretty=oneline master > 1
git log --pretty=oneline branch_A > 2

git rev-parse `diff 1 2 | tail -1 | cut -c 3-42`^

6voto

stronk7 Punkte 51

Sicherlich übersehe ich etwas, aber IMO werden alle oben genannten Probleme dadurch verursacht, dass wir immer versuchen, den Verzweigungspunkt zu finden, der in der Geschichte zurückgeht, und das verursacht alle möglichen Probleme aufgrund der verfügbaren Zusammenführungskombinationen.

Stattdessen habe ich einen anderen Ansatz verfolgt, basierend auf der Tatsache, dass beide Zweige eine Menge Geschichte teilen, genau alle Geschichte vor der Verzweigung ist 100% gleich, so dass statt zurück zu gehen, mein Vorschlag ist über vorwärts gehen (von 1st commit), auf der Suche nach der ersten Differenz in beiden Zweigen. Der Verzweigungspunkt wird einfach der Elternteil der ersten gefundenen Differenz sein.

In der Praxis:

#!/bin/bash
diff <( git rev-list "${1:-master}" --reverse --topo-order ) \
     <( git rev-list "${2:-HEAD}" --reverse --topo-order) \
--unified=1 | sed -ne 's/^ //p' | head -1

Und es löst alle meine üblichen Fälle. Sicher gibt es Grenzen, die nicht abgedeckt sind, aber... ciao :-)

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