Git 2.18 (Q2 2018) wird die --preserve-merge
Option durch Hinzufügen einer neuen Option erheblich verbessern .
" git rebase
" gelernt " --rebase-merges
", die gesamte Topologie des Commit-Graphen an eine andere Stelle zu übertragen .
(Hinweis: Git 2.22, Q2 2019, ist tatsächlich veraltet --preserve-merge
, und Git 2.25, Q1 2020, macht keine Werbung mehr in der " git rebase --help
" Ausgabe. )
Sehen Sie verpflichten 25cff9f , begehen 7543f6f , begehen 1131ec9 , begehen 7ccdf65 , begehen 537e7d6 , begehen a9be29c , begehen 8f6aed7 , begehen 1644c73 , begehen d1e8b01 , begehen 4c68e7d , begehen 9055e40 , begehen cb5206e , begehen a01c2a5 , begehen 2f6b1d1 , begehen bf5c057 (25. April 2018) von Johannes Schindelin ( dscho
) .
Siehe Commit f431d73 (25. April 2018) von Stefan Beller ( stefanbeller
) .
Siehe Commit 2429335 (25. April 2018) von Phillip Wood ( phillipwood
) .
(Zusammengeführt von Junio C Hamano - gitster
- in Commit 2c18e6a , 23. Mai 2018)
pull
: Accept --rebase-merges
, um die Branchentopologie neu zu erstellen
Ähnlich wie im preserve
Modus, in dem die --preserve-merges
Option einfach an den rebase
Befehl übergeben wird, wird im merges
Modus die --rebase-merges
Option einfach übergeben
.
Auf diese Weise können Benutzer nicht triviale Festschreibungstopologien beim Abrufen neuer Festschreibungen bequem neu definieren, ohne sie zu reduzieren.
git rebase
Die Manpage enthält jetzt einen vollständigen Abschnitt, der sich der Neugestaltung des Verlaufs durch Zusammenführungen widmet .
Extrakt:
Es gibt legitime Gründe, warum ein Entwickler Merge-Commits neu erstellen möchte: um die Zweigstellenstruktur (oder "Commit-Topologie") beizubehalten, wenn er an mehreren miteinander verbundenen Zweigen arbeitet.
Im folgenden Beispiel arbeitet der Entwickler an einem Themenzweig, der die Definition von Schaltflächen umgestaltet, und an einem anderen Themenzweig, der dieses Refactoring verwendet, um eine Schaltfläche "Fehler melden" zu implementieren.
Die Ausgabe von git log --graph --format=%s -5
kann folgendermaßen aussehen:
* Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one
Der Entwickler möchte diese Commits möglicherweise auf eine neuere Basis zurücksetzen, master
während die Zweigstellentopologie beibehalten wird , z. B. wenn erwartet wird, dass der erste Themenzweig master
viel früher als der zweite integriert wird, um beispielsweise Zusammenführungskonflikte mit Änderungen an der vorgenommenen DownloadButton
Klasse zu lösen
es in master
.
Diese Rebase kann mit der --rebase-merges
Option durchgeführt werden.
Siehe 1644c73 verpflichten für ein kleines Beispiel:
rebase-helper
--make-script
: Führen Sie ein Flag ein, um Zusammenführungen neu zu starten
Der Sequenzer hat gerade neue Befehle gelernt, mit denen die Zweigstruktur wiederhergestellt werden soll ( ähnlich --preserve-merges
, aber mit einem wesentlich weniger fehlerhaften Design ).
Lassen wir das zu rebase--helper
Aufgabenlisten mithilfe dieser Befehle generieren, die durch die neue --rebase-merges
Option ausgelöst werden .
Für eine Commit-Topologie wie diese (wobei der HEAD auf C zeigt):
- A - B - C (HEAD)
\ /
D
Die generierte Aufgabenliste würde folgendermaßen aussehen:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
Was ist der Unterschied zu --preserve-merge
?
Commit 8f6aed7 erklärt:
Es war einmal, hier dachte der Entwickler: Wäre es nicht schön, wenn beispielsweise die Patches von Git für Windows auf dem Kern-Git als Dickicht von Zweigen dargestellt und auf dem Kern-Git neu basiert würden, um dies zu tun eine Reihe von Patch-Serien pflegen?
Der ursprüngliche Versuch, dies zu beantworten, war : git rebase --preserve-merges
.
Dieses Experiment war jedoch nie als interaktive Option gedacht und wurde nur als Huckepack verwendet, git rebase --interactive
da die Implementierung dieses Befehls bereits sehr, sehr vertraut aussah: Es wurde von derselben Person entworfen, die es entworfen hat--preserve-merges
: wirklich von Ihnen.
Und mit "Mit freundlichen Grüßen" bezieht sich der Autor auf sich selbst: Johannes Schindelin ( dscho
) , der der Hauptgrund (mit einigen anderen Helden - Hannes, Steffen, Sebastian, ...) ist, dass wir Git For Windows haben (obwohl damals - 2009 - war das nicht einfach ).
Er arbeitet seit September 2015 bei Microsoft. Dies ist sinnvoll, da Microsoft Git jetzt stark nutzt und seine Dienste benötigt.
Dieser Trend begann 2013 mit TFS . Seitdem verwaltet Microsoft das größte Git-Repository der Welt ! Und, seit Oktober 2018 hat Microsoft GitHub übernommen .
Sie können Johannes in diesem Video sprechen sehen für Git Merge 2018 im April 2018 .
Einige Zeit später entschied ein anderer Entwickler (ich sehe dich an, Andreas! ;-)), dass es eine gute Idee wäre, die --preserve-merges
Kombination mit --interactive
(mit Vorbehalten!) Und dem Git-Betreuer (nun ja, dem vorläufigen Git-Betreuer) zuzulassen während Junios Abwesenheit war das vereinbart, und dann begann der Glamour des --preserve-merges
Designs ziemlich schnell und unscheinbar auseinanderzufallen.
Hier spricht Jonathan über Andreas Schwab von Suse.
Sie können einige ihrer Diskussionen im Jahr 2012 sehen .
Der Grund? Im --preserve-merges
Modus wurden die übergeordneten Elemente eines Zusammenführungs-Commits (oder eines Commits) nicht explizit angegeben, sondern
durch den an den Befehl übergebenen Commit-Namen impliziertpick
.
Dies machte es beispielsweise unmöglich, Commits neu zu ordnen .
Ganz zu schweigen davon, Commits zwischen Zweigen zu verschieben oder, Gott sei Dank, Themenzweige in zwei Teile zu teilen.
Leider haben diese Mängel auch verhindert, dass dieser Modus (dessen ursprünglicher Zweck darin bestand, die Anforderungen von Git für Windows zu erfüllen, mit der zusätzlichen Hoffnung, dass er auch für andere nützlich sein kann) die Anforderungen von Git für Windows erfüllt.
Fünf Jahre später, als es wirklich unhaltbar wurde, eine unhandliche, große Hodge-Podge-Patch-Serie von teilweise verwandten, teilweise nicht verwandten Patches in Git für Windows zu haben, die von Zeit zu Zeit auf die Kern-Tags von Git zurückgesetzt wurde (was den unverdienten Zorn des Entwicklers verdiente) Von der unglückseligen
git-remote-hg
Serie, die zuerst den konkurrierenden Ansatz von Git für Windows überholte, um später ohne Betreuer aufgegeben zu werden, war der " Git garden shears ‘ wurden geboren : ein Skript, huckepack auf das interaktiven Fütterungsmaterial, Das würde zuerst die Verzweigungstopologie der neu zu basierenden Patches bestimmen, eine Pseudo-ToDo-Liste zur weiteren Bearbeitung erstellen und das Ergebnis in eine echte ToDo-Liste umwandeln (wobei dieexec
Befehl zum "Implementieren" der fehlenden ToDo-Listenbefehle) und zum erneuten Erstellen der Patch-Serie über dem neuen Basis-Commit.
(Auf das Git Garden Shears-Skript wird in diesem Patch in Commit 9055e40 verwiesen. )
Das war im Jahr 2013.
Und es dauerte ungefähr drei Wochen, um das Design zu entwickeln und es als Out-of-Tree-Skript zu implementieren. Es ist unnötig zu erwähnen, dass die Implementierung einige Jahre brauchte, um sich zu stabilisieren, während sich das Design selbst als solide erwies.
Mit diesem Patch kommt die Güte der Git Gartenschere an git
rebase -i
sich .
Wenn Sie die --rebase-merges
Option übergeben, wird eine Aufgabenliste erstellt, die leicht verständlich ist und bei der es offensichtlich ist, wie Commits neu angeordnet werden .
Neue Zweige können durch Einfügen von label
Befehlen und Aufrufen eingeführt werden merge <label>
.
Und sobald dieser Modus stabil und allgemein anerkannt ist, können wir den Designfehler, der aufgetreten ist, ablehnen--preserve-merges
.
Git 2.19 (Q3 2018) verbessert die neue --rebase-merges
Option, indem sie funktioniert --exec
.
Die --exec
Option " " to " git rebase --rebase-merges
" platzierte die exec-Befehle an falschen Stellen, was korrigiert wurde.
Siehe Commit 1ace63b (09. August 2018) und Commit f0880f7 (06. August 2018) von Johannes Schindelin ( dscho
) .
(Zusammengeführt von Junio C Hamano - gitster
- in Commit 750eb11 , 20. August 2018)
rebase --exec
: lass es funktionieren mit --rebase-merges
Die Idee von --exec
ist, exec
nach jedem einen Anruf anzuhängen pick
.
Seit der Einführung des fixup!
/ s quash!
Festschreibungen, wurde diese Idee anzuwenden erweitert „pick, gegebenenfalls gefolgt von einer Fixup / Squash - Kette“, also wäre ein exec nicht zwischen a eingefügt werden pick
und jedes seiner entsprechenden
fixup
oder squash
Linien.
Die aktuelle Implementierung verwendet einen schmutzigen Trick , dies zu erreichen: es wird davon ausgegangen , dass es nur sind Pick / fixup / Squash - Befehle, und dann
fügt die exec
Zeilen vor jedem pick
aber den ersten und fügt einen endgültigen.
Mit den ToDo - Listen , die durch git rebase --rebase-merges
diese einfache Implementierung zeigt seine Probleme: es produziert die genauen falsche Sache , wenn es label
, reset
und merge
Befehle.
Lassen Sie uns die Implementierung ändern, um genau das zu tun, was wir wollen: Suchen Sie nach
pick
Zeilen, überspringen Sie alle Fixup- / Squash-Ketten und fügen Sie die exec
Zeile ein . Aufschäumen, ausspülen, wiederholen.
Hinweis: Wir bemühen uns, wann immer möglich vor Kommentarzeilen einzufügen , da leere Commits durch auskommentierte Auswahlzeilen dargestellt werden (und wir möchten die Ausführungszeile einer vorhergehenden Auswahl vorher einfügen solchen Zeile , nicht danach).
Fügen Sie dabei auch exec
Zeilen nach merge
Befehlen hinzu, da diese den Befehlen ähneln pick
: Sie fügen neue Festschreibungen hinzu.
Git 2.22 (Q2 2019) korrigiert die Verwendung von refs / rewritten / hierarchy zum Speichern von Rebase-Zwischenzuständen, wodurch die Hierarchie von Natur aus pro Arbeitsbaum erstellt wird.
Siehe Commit b9317d5 , Commit 90d31ff , Commit 09e6564 (07. März 2019) von Nguyễn Thái Ngọc Duy ( pclouds
) .
(Zusammengeführt von Junio C Hamano - gitster
- in Commit 917f2cd , 9. April 2019)
Stellen Sie sicher, dass refs / rewritten / pro Arbeitsbaum ist
a9be29c (Sequenzer: Refs label
erstellen, die mit dem Befehl worktree-local, 2018-04-25, Git 2.19 generiert wurden) wird refs/rewritten/
als Referenzraum pro Arbeitsbaum hinzugefügt.
Leider (mein schlechtes) gibt es einige Stellen, die aktualisiert werden müssen, um sicherzustellen, dass es wirklich pro Arbeitsbaum ist.
- add_per_worktree_entries_to_dir()
wird aktualisiert, um sicherzustellen, dass sich die Ref-Liste auf den Arbeitsbaum refs/rewritten/
anstatt auf den pro Repo bezieht .
common_list[]
wird aktualisiert, sodass git_path()
der richtige Speicherort zurückgegeben wird. Dies beinhaltet " rev-parse --git-path
".
Dieses Durcheinander wird von mir erstellt.
Ich fing an, es mit der Einführung zu beheben, refs/worktree,
wo alle Refs ohne spezielle Behandlungen pro Arbeitsbaum sein werden.
Unglückliche refs / umgeschrieben kamen vor refs / worktree, also ist dies alles, was wir tun können.
Mit Git 2.24 (Q4 2019) lernte " git rebase --rebase-merges
", verschiedene Zusammenführungsstrategien voranzutreiben und strategiespezifische Optionen an sie weiterzugeben.
Siehe Commit 476998d (04. September 2019) von Elijah Newren (newren
) .
Siehe e1fac53 begehen , begehen a63f990 , begehen 5dcdd74 , begehen e145d99 , begehen 4e6023b , begehen f67336d , begehen a9c7107 , begehen b8c6f24 , begehen d51b771 , begehen c248d32 , begehen 8c1e240 , begehen 5efed0e , begehen 68b54f6 , begehen 2e7bbac , begehen 6180b20 , begehen d5b581f (31 Jul 2019) vonJohannes Schindelin ( dscho
).
(Zusammengeführt von Junio C Hamano - gitster
- in Commit 917a319 , 18. September 2019)
Mit Git 2.25 (Q1 2020) ist die Logik, die verwendet wird, um die lokalen und globalen Refs des Arbeitsbaums voneinander zu unterscheiden, festgelegt, um die Zusammenführung zu erleichtern.
Siehe Commit f45f88b , Commit c72fc40 , Commit 8a64881 , Commit 7cb8c92 , Commit e536b1f (21. Oktober 2019) von SZEDER Gábor ( szeder
) .
(Zusammengeführt von Junio C Hamano - gitster
- in Commit db806d7 , 10. November 2019)
path.c
: Rufen Sie die match
Funktion nicht ohne Wert in auftrie_find()
Unterzeichnet von: SZEDER Gábor
'logs / refs' ist kein baumspezifischer Arbeitspfad, aber seit dem Festschreiben von b9317d55a3 ( Stellen Sie sicher, dass refs / rewritten / per-worktree, 2019-03-07, v2.22.0-rc0) ' git rev-parse --git-path
' einen falschen Pfad zurückgegeben hat wenn ein nachfolgendes ' /
' vorhanden ist:
$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/
Wir verwenden eine trie
Datenstruktur, um effizient zu entscheiden, ob ein Pfad zum allgemeinen Verzeichnis gehört oder baumspezifisch arbeitet.
Zufällig löste b9317d55a3 einen Fehler aus, der so alt ist wie die trie
Implementierung selbst, der in 4e09cf2acf hinzugefügt wurde (" path
: Gemeinsame Verzeichnisprüfung optimieren", 31.08.2015, Git v2.7.0-rc0 - Zusammenführung in Stapel 2 aufgeführt ).
Gemäß dem beschreibenden Kommentar trie_find()
sollte die angegebene Übereinstimmungsfunktion 'fn' nur für ein "/ -oder- \ 0-terminiertes Präfix des Schlüssels aufgerufen werden, für den der Versuch einen Wert enthält".
Dies ist nicht wahr: Es gibt drei Stellen, an denen trie_find () die Übereinstimmungsfunktion aufruft, aber einer von ihnen fehlt die Prüfung auf Wertexistenz.
b9317d55a3 fügte zwei neue Schlüssel hinzu trie
:
- '
logs/refs/rewritten
' und
- '
logs/refs/worktree
', neben dem bereits vorhandenen ' logs/refs/bisect
'.
Dies führte zu einem trie
Knoten mit dem Pfad ' logs/refs/
', der zuvor nicht vorhanden war und an den kein Wert angehängt ist.
Eine Abfrage nach ' logs/refs/
' findet diesen Knoten und trifft dann auf die eine Aufrufseite der match
Funktion, die nicht auf die Existenz des Werts prüft, und ruft daher die match
Funktion mit NULL
als Wert auf.
Wenn die match
Funktion check_common()
mit einem NULL
Wert aufgerufen wird, wird 0 zurückgegeben, was darauf hinweist, dass der abgefragte Pfad nicht zum allgemeinen Verzeichnis gehört, was letztendlich zu dem oben gezeigten falschen Pfad führt.
Fügen Sie die fehlende Bedingung hinzu, trie_find()
damit die Übereinstimmungsfunktion niemals mit einem nicht vorhandenen Wert aufgerufen wird.
check_common()
muss dann nicht mehr überprüfen, ob es einen Nicht-NULL-Wert hat, also entfernen Sie diese Bedingung.
Ich glaube, dass es keine anderen Pfade gibt, die eine ähnliche Scheinausgabe verursachen könnten.
AFAICT Die einzige andere Taste, die dazu führt, dass die Übereinstimmungsfunktion mit einem NULL
Wert aufgerufen wird, ist ' co
' (wegen der Tasten ' common
' und ' config
').
Da sie sich jedoch nicht in einem Verzeichnis befinden, das zum allgemeinen Verzeichnis gehört, wird der resultierende baumspezifische Pfad erwartet.
git --rebase-merges
wird letztendlich das alte ersetztgit --preserve-merges
. Siehe meine Antwort unten