Kurze Antwort
Sie haben die Tatsache, dass Sie ausgeführt wurden git push
, weggelassen , den folgenden Fehler erhalten und dann ausgeführt git pull
:
To git@bitbucket.org:username/test1.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Obwohl Git versucht, hilfreich zu sein, ist der Ratschlag "Git Pull" höchstwahrscheinlich nicht das, was Sie tun möchten .
Wenn du bist:
- Die Arbeit an einem „Feature Zweig“ oder „Entwicklerzweig“ allein , dann können Sie laufen
git push --force
die Fernbedienung mit Ihrer Post-rebase Commits zu aktualisieren ( wie pro user4405677 Antwort ).
- Wenn Sie mit mehreren Entwicklern gleichzeitig an einem Zweig arbeiten, sollten Sie ihn wahrscheinlich gar nicht erst verwenden
git rebase
. Um dev
mit Änderungen von zu aktualisieren master
, sollten Sie, anstatt zu laufen git rebase master dev
, laufen, git merge master
während Sie eingeschaltet sind dev
( gemäß Justins Antwort ).
Eine etwas längere Erklärung
Jeder Commit-Hash in Git basiert auf einer Reihe von Faktoren, von denen einer der Hash des Commits ist, der davor steht.
Wenn Sie Commits neu anordnen, ändern Sie die Commit-Hashes. Durch erneutes Basieren (wenn es etwas tut) werden Commit-Hashes geändert. Das Ergebnis des Ausführens git rebase master dev
, bei dem dev
die Synchronisierung nicht stimmt master
, erzeugt neue Commits (und damit Hashes) mit demselben Inhalt wie die aktivierten, dev
jedoch mit den master
vor ihnen eingefügten Commits .
Sie können auf verschiedene Weise in eine solche Situation geraten. Zwei Möglichkeiten, die ich mir vorstellen kann:
- Sie könnten Verpflichtungen eingehen, auf
master
die Sie Ihre dev
Arbeit stützen möchten
- Sie hätten Commits auf ,
dev
die bereits an einem entfernten geschoben worden sind, die Sie dann zu ändern gehen (reword Commit - Nachrichten, Neuordnungs Commits, Squash Commits, etc.)
Lassen Sie uns besser verstehen, was passiert ist - hier ein Beispiel:
Sie haben ein Repository:
2a2e220 (HEAD, master) C5
ab1bda4 C4
3cb46a9 C3
85f59ab C2
4516164 C1
0e783a3 C0
Anschließend ändern Sie die Commits.
git rebase --interactive HEAD~3 # Three commits before where HEAD is pointing
(Hier müssen Sie mein Wort dafür nehmen: Es gibt eine Reihe von Möglichkeiten, Commits in Git zu ändern. In diesem Beispiel habe ich die Zeit von geändert C3
, aber Sie fügen neue Commits ein, ändern Commit-Nachrichten, ordnen Commits neu an. Squashing Commits zusammen usw.)
ba7688a (HEAD, master) C5
44085d5 C4
961390d C3
85f59ab C2
4516164 C1
0e783a3 C0
Hier ist es wichtig zu beachten, dass die Commit-Hashes unterschiedlich sind. Dies ist das erwartete Verhalten, da Sie etwas (irgendetwas) an ihnen geändert haben. Das ist okay, ABER:
Wenn Sie versuchen zu pushen, wird ein Fehler angezeigt (und ein Hinweis darauf, dass Sie ausgeführt werden sollten git pull
).
$ git push origin master
To git@bitbucket.org:username/test1.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Wenn wir laufen git pull
, sehen wir dieses Protokoll:
7df65f2 (HEAD, master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 (origin/master) C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0
Oder anders gezeigt:
Und jetzt haben wir doppelte Commits vor Ort. Wenn wir laufen git push
würden, würden wir sie an den Server senden.
Um dieses Stadium nicht zu erreichen, hätten wir laufen können git push --force
(wo wir stattdessen gelaufen sind git pull
). Dies hätte unsere Commits mit den neuen Hashes ohne Probleme an den Server gesendet. Um das Problem zu diesem Zeitpunkt zu beheben, können wir vor dem Ausführen auf Folgendes zurücksetzen git pull
:
Schauen Sie sich das reflog ( git reflog
) an, um zu sehen, was der Commit-Hash war, bevor wir ausgeführt wurden git pull
.
070e71d HEAD@{1}: pull: Merge made by the 'recursive' strategy.
ba7688a HEAD@{2}: rebase -i (finish): returning to refs/heads/master
ba7688a HEAD@{3}: rebase -i (pick): C5
44085d5 HEAD@{4}: rebase -i (pick): C4
961390d HEAD@{5}: commit (amend): C3
3cb46a9 HEAD@{6}: cherry-pick: fast-forward
85f59ab HEAD@{7}: rebase -i (start): checkout HEAD~~~
2a2e220 HEAD@{8}: rebase -i (finish): returning to refs/heads/master
2a2e220 HEAD@{9}: rebase -i (start): checkout refs/remotes/origin/master
2a2e220 HEAD@{10}: commit: C5
ab1bda4 HEAD@{11}: commit: C4
3cb46a9 HEAD@{12}: commit: C3
85f59ab HEAD@{13}: commit: C2
4516164 HEAD@{14}: commit: C1
0e783a3 HEAD@{15}: commit (initial): C0
Oben sehen wir, dass dies ba7688a
das Commit war, an dem wir vor dem Laufen teilgenommen haben git pull
. Mit diesem Commit-Hash in der Hand können wir auf that ( git reset --hard ba7688a
) zurücksetzen und dann ausführen git push --force
.
Und wir sind fertig.
Aber warte, ich habe die Arbeit weiterhin auf die doppelten Commits gestützt
Wenn Sie irgendwie nicht bemerkt haben, dass die Commits dupliziert wurden, und weiterhin auf doppelten Commits arbeiten, haben Sie sich wirklich selbst durcheinander gebracht. Die Größe des Chaos ist proportional zur Anzahl der Commits, die Sie auf den Duplikaten haben.
Wie das aussieht:
3b959b4 (HEAD, master) C10
8f84379 C9
0110e93 C8
6c4a525 C7
630e7b4 C6
070e71d (origin/master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0
Oder anders gezeigt:
In diesem Szenario möchten wir die doppelten Commits entfernen, aber die darauf basierenden Commits beibehalten - wir möchten C6 bis C10 beibehalten. Wie bei den meisten Dingen gibt es eine Reihe von Möglichkeiten, dies zu tun:
Entweder:
- Erstellen Sie einen neuen Zweig beim letzten duplizierten Commit 1 ,
cherry-pick
jedes Commit (C6 bis einschließlich C10) für diesen neuen Zweig, und behandeln Sie diesen neuen Zweig als kanonisch.
- Führen Sie aus
git rebase --interactive $commit
, wo $commit
sich das Commit vor den beiden duplizierten Commits befindet. 2 . Hier können wir die Zeilen für die Duplikate sofort löschen.
1 Es spielt keine Rolle, welche der beiden Sie wählen ba7688a
oder ob sie gut 2a2e220
funktionieren.
2 Im Beispiel wäre es 85f59ab
.
TL; DR
Stellen Sie ein advice.pushNonFastForward
auf false
:
git config --global advice.pushNonFastForward false