Wie rette ich / Re-synchronisiert, nachdem jemand ein Fütterungsmaterial oder ein Rücksetzen auf einen veröffentlichten Zweig schiebt?
-
28-09-2019 - |
Frage
Wir haben alle gehört, dass man sollte nie rebase Arbeit veröffentlicht, dass es gefährlich ist, usw. Allerdings habe ich keine Rezepte für den Umgang mit der Situation im Falle einer rebase is geschrieben gesehen veröffentlicht .
Nun, tun beachten Sie, dass dies nur dann wirklich möglich, wenn das Repository nur durch eine bekannte (und vorzugsweise kleine) Gruppe von Menschen geklont wird, dass so wer das Fütterungsmaterial drückt oder Reset jeden mitteilt sonst kann, dass sie zu achten brauchen nächstes Mal, wenn sie holen (!).
Eine offensichtliche Lösung, dass ich gesehen habe, wird funktionieren, wenn Sie keine lokalen Commits auf foo
haben und es indexiert wird:
git fetch
git checkout foo
git reset --hard origin/foo
Dies wird einfach den lokalen Zustand der foo
zugunsten seiner Geschichte gemäß dem Remote-Repository wegzuwerfen.
Aber wie geht man mit der Situation, wenn man erhebliche lokale Änderungen an diesem Zweig begangen hat?
Lösung
Kommen wir zurück synchron nach einer geschoben rebase ist wirklich nicht so in den meisten Fällen kompliziert.
git checkout foo
git branch old-foo origin/foo # BEFORE fetching!!
git fetch
git rebase --onto origin/foo old-foo foo
git branch -D old-foo
Ie. zuerst setzen Sie war ursprünglich ein Lesezeichen für die Position der fernen Zweig, dann verwenden Sie, dass Ihre lokalen Commits von diesem Punkt wiederholen weiter auf umbasiert Fern Zweig.
ist Umbasierung wie Gewalt: Wenn es nicht Ihr Problem lösen, brauchen Sie nur mehr davon. ?
Sie können dies tun, ohne das Lesezeichen natürlich, wenn Sie die Pre-rebase origin/foo
begehen ID nachschlagen und Verwendung der.
Dies ist auch, wie man mit der Situation umgehen, wenn Sie ein Lesezeichen machen vergessen vor abgerufen werden. Nichts ist verloren - Sie müssen nur die reflog überprüfen für den Remote-Zweig:
git reflog show origin/foo | awk '
PRINT_NEXT==1 { print $1; exit }
/fetch: forced-update/ { PRINT_NEXT=1 }'
Dies druckt die ID verpflichten, dass origin/foo
zu spitz, bevor die jüngsten holen, dass seine Geschichte geändert.
Sie können dann einfach
git rebase --onto origin/foo $commit foo
Andere Tipps
würde ich das sagen erholt sich von stromaufwärts rebase Abschnitt des git- rebase Manpage deckt so ziemlich alles.
Es ist wirklich nicht anders aus Ihrer eigenen rebase erholt - Sie bewegen einen Zweig, und rebase alle Zweige, die ihn auf seine neue Position in ihrer Geschichte hatten
. Beginnend mit git 1.9 / 2.0 Q1 2014 wird Sie nicht Ihre vorherigen Zweig Ursprung markieren müssen, bevor sie auf dem neu geschrieben Upstream-Zweig Rebasing, wie in Aristoteles pagaltzis 's Antwort :
Siehe verpflichten 07d406b und begehen d96855f :
Nach der Arbeit auf dem
topic
Zweig mitgit checkout -b topic origin/master
erstellt, die Geschichte der Fernverfolgung Zweigorigin/master
kann zurückgespult und neu aufgebaut wurden, zu einer Geschichte dieser Form führt:
o---B1
/
---o---o---B2--o---o---o---B (origin/master)
\
B3
\
Derived (topic)
wo
origin/master
bei CommitsB3
zu Punkt verwendet,B2
,B1
und jetzt zeigt es aufB
und Ihrtopic
Zweig wurde oben drauf zurück beginnt, alsorigin/master
beiB3
war.In diesem Modus wird die reflog von
origin/master
B3
als Gabelpunkt zu finden, so dass dietopic
oben auf die aktualisierten indexiert werden könnenorigin/master
durch:
$ fork_point=$(git merge-base --fork-point origin/master topic)
$ git rebase --onto origin/master $fork_point topic
Deshalb ist der git merge-base
Befehl hat eine neue Option:
--fork-point::
Hier finden Sie die Stelle, an der ein Zweig (oder eine Geschichte, dass führt zu
<commit>
) von einem anderen Zweig gegabelt (oder jeder Referenz)<ref>
.
Das sieht nicht nur für die gemeinsamen Vorfahren der beiden Commits, aber berücksichtigt auch die reflog von<ref>
zu sehen, ob die Geschichte, die zu<commit>
aus einer früheren Inkarnation der Zweig gegabelt<ref>
.
Der „
git pull --rebase
“ Befehl berechnet der Gabelpunkt des Zweig umbasiert wobei die reflog Einträge des „base
“ -Zweig (normalerweise ein Fernverfolgung Zweig), um die Arbeit des Zweig beruhte auf, um mit dem Fall fertig zu werden in welche die „Basis“ Zweig hat gewesen zurückgespult und wiederaufgebaut.
Zum Beispiel, wenn die Geschichte sieht aus wie, wo:
- die aktuelle Spitze des „
base
“ Zweig ist aufB
, aber früher Abruf festgestellt, dass seine SpitzeB3
verwendet werden sollte und dannB2
und dannB1
vor dem aktuellen bekommen begehen, und- die Niederlassung auf die neuesten „Basis“ indexiert werden basiert auf begehen
B3
,es versucht
B3
zu finden, indem sie durch die Ausgabe von „git rev-list --reflog base
“ gehen (das heißtB
,B1
,B2
,B3
), bis er eine findet begehen, dass ein Vorfahre der aktuellen Spitze „Derived (topic)
“.Intern haben wir
get_merge_bases_many()
, dass dies mit einem Sprung berechnen kann.
Wir würden einen Merge-Basis zwischenDerived
wollen und einer fiktiven merge commit, dass durch die Zusammenlegung aller historischen Spitzen „base (origin/master)
“ führen würde.
Wenn eine solche exist begehen, sollten wir ein einzelnes Ergebnis bekommen, das ist genau eine der reflog Einträge von „base
“ entsprechen.
Git 2.1 (Q3 2014) fügen Sie diese Funktion machen robusteres dazu: siehe begehen 1e0dacd von John Keeping (johnkeeping
)
korrekt verarbeiten das Szenario, in dem wirhat die folgende Topologie:
C --- D --- E <- dev
/
B <- master@{1}
/
o --- B' --- C* --- D* <- master
Dabei gilt:
-
B'
ist ein Fest-up-Version vonB
, die nicht pflaster identisch mitB
wird; -
C*
undD*
sind pflaster identisch mitC
undD
jeweils und Konflikt textlich, wenn in der falschen Reihenfolge angewandt wird; -
E
hängt textlich aufD
.
Das richtige Ergebnis von git rebase master dev
ist, dass B
als Gabelpunkt dev
und master
identifiziert wird, so dass C
, D
, E
sind die Commits, dass Bedarf an master
wiederholt werden; aber C
und D
sind pflaster identisch mit C*
und D*
und so kann fallen gelassen werden, so dass das Endergebnis ist:
o --- B' --- C* --- D* --- E <- dev
Wenn der Gabelpunkt nicht identifiziert, dann Kommissionierung B
auf einen Zweig enthält B'
führt zu einem Konflikt und wenn die Patch-identisch Commits nicht korrekt dann C
auf einen Zweig Kommissionierung identifiziert enthält D
(oder äquivalent D*
) ergibt ein Konflikt.