Verschieben von festgeschriebenen (aber nicht übertragenen) Änderungen in einen neuen Zweig nach dem Ziehen

460

Ich habe einiges an Arbeit geleistet ("Ihre Niederlassung liegt um 37 Commits vor 'origin / master'."), Die eigentlich eher in eine eigene Niederlassung als in eine eigene hätte gehen sollen master. Diese Commits sind nur auf meinem lokalen Computer vorhanden und wurden nicht übertragen origin, aber die Situation ist etwas kompliziert, da andere Entwickler darauf hingewiesen haben origin/masterund ich diese Änderungen vorgenommen habe.

Wie verschiebe ich meine 37 lokalen Commits rückwirkend in eine neue Niederlassung? Basierend auf den Dokumenten scheint es, dass dies getan werden sollte git rebase --onto my-new-branch masteroder ...origin/mastersollte, aber beide geben mir nur den Fehler "fatal: Benötigte eine einzige Revision". man git-rebasesagt nichts über das Bereitstellen einer Revision aus rebaseund seine Beispiele tun dies nicht, daher habe ich keine Ahnung, wie dieser Fehler behoben werden kann.

(Beachten Sie, dass dies kein Duplikat von Verschieben vorhandener, nicht festgeschriebener Arbeit in einen neuen Zweig in Git ist oder wie ich meine lokalen nicht festgeschriebenen Änderungen in einem anderen Git-Zweig zusammenführe, da diese Fragen nicht festgeschriebene Änderungen im lokalen Arbeitsbaum betreffen, nicht Änderungen, die vorhanden sind wurde vor Ort begangen.)

Dave Sherohman
quelle
Schauen Sie sich diese Lösung an . Scheint einfach und sauber zu sein.
Tony
Schauen Sie sich diese Lösung an . Scheint einfach und sauber zu sein.
Tony

Antworten:

518

Dies sollte in Ordnung sein, da Sie Ihre Commits noch nirgendwo anders gepusht haben und Sie den Verlauf Ihrer Niederlassung danach neu schreiben können origin/master. Zuerst würde ich a ausführen git fetch origin, um sicherzustellen, dass origin/masteres auf dem neuesten Stand ist. Angenommen, Sie sind gerade aktiv master, sollten Sie in der Lage sein:

git rebase origin/master

... , die alle Ihre Commits wiedergeben , die nicht in origin/masterauf origin/master. Die Standardaktion von Rebase besteht darin, Zusammenführungs-Commits zu ignorieren (z. B. diejenigen, die Sie git pullwahrscheinlich eingeführt haben), und es wird nur versucht, den von jedem Ihrer Commits eingeführten Patch auf anzuwenden origin/master. (Möglicherweise müssen Sie unterwegs einige Konflikte lösen.) Anschließend können Sie Ihren neuen Zweig basierend auf dem Ergebnis erstellen:

git branch new-work

... und setzen Sie dann Ihren masterRücken zurück auf origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

Wenn Sie mit dieser Art von Manipulation Zweigen tun git branch, git resetetc. Ich finde nützlich es häufig zu betrachten das Diagramm begeht mit gitk --alloder einem ähnlichen Werkzeug, nur um zu überprüfen , dass ich verstehe , wo alle die verschiedenen Refs zeigen.

Alternativ hätten Sie einfach einen Themenzweig erstellen können, der darauf basiert, wo sich Ihr Master an erster Stelle befindet ( git branch new-work-including-merges), und dann masterwie oben zurückgesetzt. Da Ihr origin/masterThemenzweig jedoch Zusammenführungen von enthält und Sie Ihre Änderungen noch nicht vorangetrieben haben, würde ich vorschlagen, eine Neubasis durchzuführen, damit der Verlauf aufgeräumter wird. (Wenn Sie Ihren Themenzweig schließlich wieder zum Master zusammenführen, werden die Änderungen offensichtlicher.)

Mark Longair
quelle
8
@Olie: Nein, die Antwort ist korrekt unter den Annahmen in der Frage und denen, die ich oben in der Antwort dargelegt habe. Die Commits, die sich in einem separaten neuen Zweig befinden sollten, sind bereits vorhanden master. Die Rebase schreibt den masterZweig so um, dass die neuen Commits linear über dem Zweig liegen origin/master, und git branch new-workerstellt dann einen new-workZweig, der auf die Spitze master(des aktuellen Zweigs) zeigt, ohne den aktuellen Zweig auf zu schalten new-work. new-workEnthält nun also alle neuen Commits. Dann verschiebt der Reset den aktuellen Zweig (noch master) zurück zu origin/master.
Mark Longair
1
@ Quintesse: Es tut mir sehr leid, wenn Sie Arbeit verloren haben, aber ich bin sicher, dass diese Antwort für die vom ursprünglichen Fragesteller beschriebene Situation korrekt ist. (Ich habe gerade auf Olies Bemerkungen geantwortet, die hoffentlich klarstellen.) Für den Fall, dass es hilft, Ihre Arbeit zurückzubekommen, sollte ich sagen, wenn Ihre Arbeit in den letzten Tagen begangen wurde (eine der Annahmen in dieser Frage und Antwort ) Sie sollten es leicht über das Git-Reflog abrufen können.
Mark Longair
5
@Olie: Vielleicht eine bessere Art zu erklären: Zweige in Git sind wie Labels, die auf ein bestimmtes Commit verweisen. Sie werden automatisch in neue Commits verschoben, wenn Sie sie in diesem Zweig erstellen oder auf git resetverschiedene andere Arten verschoben werden können. Das git branch new-workheißt nur "Erstellen Sie einen Zweig, der auf dieses Commit zeigt, während ich in meinem aktuellen Zweig bleibe (der in diesem Fall Master ist)". Es gibt also keine Notwendigkeit , einen Befehl haben , dass bewegt sich die Festschreibungen von Meister zu den neuen Zweig - man muss nur eine Niederlassung schaffen es , und wenn Sie Master - Reset wird der neue Zweig links , wo Meister war
Mark Longair
1
Ein bisschen zu spät zur Party, aber @Olie, nur weil der Git-Status in der neuen Filiale die Commits vor dem Master nicht anzeigt, heißt das nicht, dass sie nicht wirklich da sind (vorausgesetzt, Sie waren deshalb besorgt). Versuchen Sie, den neuen Zweig zum Ursprung zu bringen: Sie werden sehen, dass die Commits da sind
Félix Gagnon-Grenier
2
@ FélixGagnon-Grenier, mach dir keine Sorgen um "spät" - es gibt immer Leute, die alte Fragen nachschlagen und jede Klärung hilft. Vielen Dank! :)
Olie
148

Wenn Sie eine geringe Anzahl von Commits haben und es Ihnen egal ist, ob diese zu einem Mega-Commit kombiniert werden, funktioniert dies gut und ist nicht so beängstigend wie git rebase:

Entfernen Sie die Dateien (ersetzen Sie 1 durch Anzahl der Commits).

git reset --soft HEAD~1

Erstellen Sie einen neuen Zweig

git checkout -b NewBranchName

Fügen Sie die Änderungen hinzu

git add -A

ein Commit machen

git commit -m "Whatever"
Stachu
quelle
5
Verwenden Sie bitte, um ein leicht verständliches Diagramm anzuzeigen git log --all --decorate --oneline --graph.
EliuX
Hey @EliuX - mir fehlt hier die Relevanz. Können Sie erweitern?
Stachu
Dies ist etwas Nützliches, um zu überprüfen, ob Sie das gewünschte Ergebnis in dem erhalten haben, was Sie getan haben
EliuX
4
Danke!! Dies ist eine sehr einfache Lösung und es hat perfekt funktioniert !!
Chris Sim
90

Ich blieb bei dem gleichen Problem. Ich habe die einfachste Lösung gefunden, die ich gerne teile.

1) Erstellen Sie einen neuen Zweig mit Ihren Änderungen.

git checkout -b mybranch

2) (Optional) Neuen Zweigcode auf Remote-Server übertragen.

git push origin mybranch

3) Kasse zurück zum Hauptzweig.

git checkout master

4) Setzen Sie den Hauptzweigcode mit dem Remote-Server zurück und entfernen Sie das lokale Commit.

git reset --hard origin/master
NiRmaL
quelle
10
Das ist wirklich der einfachste Weg
dhilt
4
Sie können Schritt 2 weglassen. Ich gehe davon aus, dass sich git in der Zeit seit der Top-Antwort geändert hat und dieses Verfahren zuvor nicht erlaubt war.
Sebastian
Dies ist meiner Meinung nach die beste Antwort.
Macindows
1
Diese Antwort muss nach oben verschoben werden. Vielen Dank.
Amit
27

Eine weitere Möglichkeit ist die Annahme, dass Zweig1 - Zweig mit festgeschriebenen Änderungen Zweig2 - ein wünschenswerter Zweig ist

git fetch && git checkout branch1
git log

Wählen Sie Commit-IDs aus, die Sie verschieben möchten

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Setzen Sie nun nicht gepusste Commits vom ersten Zweig zurück

git fetch && git checkout branch1
git reset --soft HEAD~1
Andriy
quelle
5
Cherry-Pick ist wirklich der beste Befehl zum Kopieren / Verschieben eines einzelnen Commits. wenn Geschichte Gepäck für Ihre Zwecke ist.
John Neuhaus
Dies ist bisher die bequemste Antwort auf die Frage. Danke für den Befehl!
Farah
Können Sie Ihren letzten Kommentar aktualisieren, wobei 1 oder n die Anzahl der nicht gepushten Commits ist? Dies ist immer noch eine wirklich gute Lösung für diese Frage.
ChAlexey
9

Alternativ können Sie direkt nach dem Festschreiben des falschen Zweigs die folgenden Schritte ausführen:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Ich kann mir vorstellen, dass es für die Schritte eins und zwei einen einfacheren Ansatz gibt.

Andreas B.
quelle
6

Wie wäre es mit:

  1. Vom aktuellen KOPF abzweigen.
  2. Stellen Sie sicher, dass Sie auf dem Master sind , nicht auf Ihrem neuen Zweig.
  3. git reset Zurück zum letzten Commit, bevor Sie Änderungen vorgenommen haben.
  4. git pull um nur die Fernbedienungsänderungen erneut abzurufen, die Sie beim Zurücksetzen weggeworfen haben.

Oder explodiert das, wenn Sie versuchen, den Zweig erneut zusammenzuführen?

Tim Keating
quelle
2
Ah, dies ist im Grunde die Option B, die oben von @ Mark-Longair beschrieben wurde
Tim Keating,
2

Hier ist ein viel einfacherer Weg:

  1. Erstellen Sie einen neuen Zweig

  2. Führen Sie in Ihrem neuen Zweig Folgendes aus: git merge masterDadurch werden Ihre festgeschriebenen (nicht übertragenen) Änderungen in Ihrem neuen Zweig zusammengeführt

  3. Löschen Sie Ihren lokalen Hauptzweig git branch -D masterVerwenden Sie -Dstatt, -dweil Sie das Löschen des Zweigs erzwingen möchten.

  4. Führen Sie einfach eine git fetchin Ihrer Hauptniederlassung und eine git pullin Ihrer Hauptniederlassung durch, um sicherzustellen, dass Sie den neuesten Code Ihres Teams haben.

Ein Kok
quelle
1

Ein einfacherer Ansatz, den ich verwendet habe (vorausgesetzt, Sie möchten 4 Commits verschieben):

git format-patch HEAD~4

(Suchen Sie in dem Verzeichnis, aus dem Sie den letzten Befehl für die 4 .patchDateien ausgeführt haben.)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Dann:

git apply /path/to/patch.patch

In welcher Reihenfolge auch immer Sie wollten.

user1429980
quelle
0
  1. Kasse frische Kopie Ihrer Quellen

    git clone ........

  2. Machen Sie einen Zweig von der gewünschten Position

    git checkout {position} git checkout -b {branch-name}

  3. Remote-Repository hinzufügen

    git remote add shared ../{original sources location}.git

  4. Holen Sie sich Remote-Quellen

    git fetch shared

  5. Kasse gewünschte Filiale

    git checkout {branch-name}

  6. Quellen zusammenführen

    git merge shared/{original branch from shared repository}

Sergey Kabashnyuk
quelle
0

Für mich war das der beste Weg:

  1. Suchen Sie nach Änderungen und führen Sie Konflikte zusammen git fetch
  2. Erstellen Sie einen neuen Zweig git branch my-changesund drücken Sie auf Remote
  3. Wechseln Sie in den neu erstellten Zweig git master -u upstream-branch remotes/origin/my-changes
  4. Übertragen Sie Ihre Commits auf die neue Upstream-Niederlassung.
  5. Wechseln Sie zurück zum vorherigen Upstream git branch master --set-upstream-to remotes/origin/master
Sebastian
quelle