it-swarm.com.de

Verschieben Sie die letzten Commits mit Git in einen neuen Zweig

Ich möchte die letzten verschiedenen Commits, die ich zu einem Master gemacht habe, in einen neuen Zweig verschieben und den Master vor dem Commit wieder aufnehmen. Leider ist mein Git-Fu noch nicht stark genug.

Das heißt Wie kann ich davon gehen?

master A - B - C - D - E

zu diesem

newbranch     C - D - E
             /
master A - B 
4108

Umzug in eine neue Niederlassung

WARNING: Diese Methode funktioniert, weil Sie mit dem ersten Befehl einen neuen Zweig erstellen: git branch newbranch. Wenn Sie Commits in einen vorhandenen Zweig verschieben möchten, müssen Sie Ihre Änderungen im vorhandenen Zweig zusammenführen, bevor Sie git reset --hard HEAD~3 ausführen (siehe Umzug in einen vorhandenen Zweigunten. Wenn Sie Ihre Änderungen nicht zuerst zusammenführen, gehen sie verloren.

Wenn keine anderen Umstände vorliegen, kann dies leicht durch Verzweigen und Zurückrollen durchgeführt werden.

# Note: Any changes not committed will be lost.
git branch newbranch      # Create a new branch, saving the desired commits
git reset --hard HEAD~3   # Move master back by 3 commits (GONE from master)
git checkout newbranch    # Go to the new branch that still has the desired commits

Aber stellen Sie sicher, wie viele Verpflichtungen Sie zurückgeben. Alternativ können Sie anstelle von HEAD~3 einfach den Hash des Festschreibens angeben (oder den Verweis wie Origin/master), auf den Sie auf dem Zweig master (/ current) zurückkehren möchten, z :

git reset --hard a1b2c3d4

* 1 Sie werden nur _ Commits aus dem Master-Zweig "verlieren", aber keine Sorge, Sie haben diese Commits in einer neuen Niederlassung!

WARNING: Ab Git-Version 2.0 und höher benötigen Sie eine neue git rebase-Option während der Rebase, wenn Sie später den neuen Zweig (master) des neuen Zweigs --no-fork-point benötigen, um die Übertragungen zu vermeiden. Wenn Sie branch.autosetuprebase always setzen, wird dies wahrscheinlicher. Siehe John Mellors Antwort für Details.

Umzug in eine bestehende Niederlassung

Wenn Sie Ihre Commits in einen vorhandenen Zweig verschieben möchten, sieht das so aus:

git checkout existingbranch
git merge master
git checkout master
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.
git checkout existingbranch
5244
sykora

Für diejenigen, die sich fragen, warum es funktioniert (wie ich zuerst war):

Sie möchten zu C zurückkehren und D und E in den neuen Zweig verschieben. So sieht es zunächst aus:

A-B-C-D-E (HEAD)
        ↑
      master

Nach git branch newBranch:

    newBranch
        ↓
A-B-C-D-E (HEAD)
        ↑
      master

Nach git reset --hard HEAD~2:

    newBranch
        ↓
A-B-C-D-E (HEAD)
    ↑
  master

Da ein Zweig nur ein Zeiger ist, zeigte master auf den letzten Commit. Wenn Sie newBranch erstellt haben, haben Sie einfach einen neuen Zeiger auf den letzten Commit gesetzt. Dann haben Sie mit git reset den master pointer zwei Commits zurückgeschoben. Da Sie newBranch jedoch nicht verschoben haben, weist dies immer noch auf das Commit hin, das es ursprünglich getan hat.

893
Ryan Lundy

Im Algemeinen...

Die von Sykora offenbarte Methode ist in diesem Fall die beste Option. Aber manchmal ist es nicht die einfachste und keine allgemeine Methode. Für eine allgemeine Methode verwenden Sie git cherry-pick:

Um das zu erreichen, was OP will, ist es ein zweistufiger Prozess:

Schritt 1 - Notieren Sie sich, welche Commits von einem Master auf einem _ newbranch festgelegt werden sollen

Execute

git checkout master
git log

Beachten Sie die Hashwerte von (etwa 3) Commits, die Sie für newbranch wünschen. Hier werde ich verwenden:
C-Commit: 9aa1233
D-Commit: 453ac3d
E-Commit: 612ecb3 

Hinweis: Sie können die ersten sieben Zeichen oder .__ verwenden. der ganze Commit-Hash

Schritt 2 - Legen Sie sie auf die newbranch

git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233

ODER (in Git 1.7.2+ verwenden Sie Bereiche)

git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233

git cherry-pick wendet diese drei Commits auf newbranch an.

372
Ivan

Eine weitere Möglichkeit, dies zu tun, indem nur 2 Befehle verwendet werden. Behält auch Ihren aktuellen Arbeitsbaum bei.

git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit

Alte Version - bevor ich git branch -f erfuhr

git checkout -b newbranch # switch to a new branch
git Push . +HEAD~3:master # make master point to some older commit 

In der Lage zu sein, Push zu . zu wechseln, ist ein guter Trick.

275
aragaer

Die meisten vorherigen Antworten sind gefährlich falsch!

Mach das nicht:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

Wenn Sie git rebase (oder git pull --rebase) das nächste Mal ausführen, werden diese 3 Commits unbemerkt von newbranch verworfen! (siehe Erklärung unten)

Stattdessen:

git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick [email protected]{2}
  • Zuerst werden die 3 letzten Commits verworfen (--keep ist wie --hard, aber sicherer, da fehlgeschlagen wird, anstatt nicht festgeschriebene Änderungen wegzuwerfen).
  • Dann gibt es newbranch ab.
  • Dann greift es die 3 Commits zurück auf newbranch. Da sie nicht mehr von einem Zweig referenziert werden, geschieht dies durch die Verwendung von gits reflog : [email protected]{2} ist das Commit, das HEAD verwendet hat, um sich auf 2 Vorgänge zu beziehen, dh bevor wir 1. ausgecheckt haben newbranch und 2. used git reset die 3 Commits verwerfen.

Achtung: Der Reflog ist standardmäßig aktiviert. Wenn Sie ihn jedoch manuell deaktiviert haben (z. B. durch Verwendung eines "bloßen" Git-Repository), können Sie die 3 Commits nicht zurückholen, nachdem Sie git reset --keep HEAD~3 ausgeführt haben.

Eine Alternative, die sich nicht auf den Reflog stützt, ist:

# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3

(Wenn Sie möchten, können Sie @{-1} - den zuvor ausgecheckten Zweig - anstelle von oldbranch schreiben).


Technische Erklärung

Warum würde git rebase die 3 Commits nach dem ersten Beispiel verwerfen? Dies liegt daran, dass git rebase ohne Argumente standardmäßig die Option --fork-point aktiviert, die den lokalen Reflog verwendet, um zu versuchen, robust gegenüber dem Upstream-Zweig zu sein, der erzwungen wird.

Angenommen, Sie haben Origin/Master verlassen, als sie die Commits M1, M2, M3 enthielt, und dann selbst drei Commits gemacht:

M1--M2--M3  <-- Origin/master
         \
          T1--T2--T3  <-- topic

aber dann schreibt jemand die Geschichte um, indem er Origin/Master zwingt, M2 zu entfernen:

M1--M3'  <-- Origin/master
 \
  M2--M3--T1--T2--T3  <-- topic

Mit Ihrem lokalen Reflog kann git rebase sehen, dass Sie sich von einer früheren Inkarnation des Origin/master-Zweigs abgezweigt haben und daher die M2- und M3-Commits nicht wirklich zu Ihrem Zweigzweig gehören. Daher wird vernünftigerweise angenommen, dass Sie M2 nicht mehr in Ihrem Zweigzweig haben möchten, da M2 aus dem Upstream-Zweig entfernt wurde, nachdem der Zweigzweig neu erstellt wurde:

M1--M3'  <-- Origin/master
     \
      T1'--T2'--T3'  <-- topic (rebased)

Dieses Verhalten ist sinnvoll und ist im Allgemeinen das Richtige bei der Umbasierung.

Der Grund dafür, dass die folgenden Befehle fehlschlagen:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

liegt daran, dass sie den reflog im falschen Zustand lassen. Git sieht, dass newbranch den Upstream-Zweig bei einer Revision, die die 3 Commits enthält, abgezweigt hat. Dann schreibt reset --hard die Historie des Upstreams, um die Commits zu entfernen. Daher werden beim nächsten Ausführen von git rebase diese wie alle anderen Commits verworfen, aus denen entfernt wurde der stromaufwärts.

In diesem speziellen Fall möchten wir jedoch, dass diese 3 Commits als Teil des Zweigzweiges betrachtet werden. Um dies zu erreichen, müssen wir bei der früheren Revision, die die 3 Commits nicht enthält, den Upstream abspalten. Das ist, was meine vorgeschlagenen Lösungen tun, daher belassen sie beide den reflog im richtigen Zustand.

Weitere Einzelheiten finden Sie in der Definition von --fork-point in git rebase und git merge-base docs.

251
John Mellor

Viel einfachere Lösung mit Git Stash

Ob: 

  • Ihr Hauptzweck besteht darin, master und 
  • Sie möchten die Dateiänderungen beibehalten, kümmern sich aber nicht besonders um die fehlerhaften Commit-Nachrichten und
  • Sie haben noch nicht gedrückt, und
  • Sie möchten, dass dies mit temporären Verzweigungen, dem Festlegen von Hashwerten und anderen Kopfschmerzen einfach und nicht kompliziert ist

Dann ist das Folgende viel einfacher (beginnend mit dem Zweig master, der drei fehlerhafte Commits hat):

git reset HEAD~3
git stash
git checkout newbranch
git stash pop

Was das macht, nach Zeilennummer

  1. Macht die letzten drei Commits (und ihre Nachrichten) für master rückgängig, lässt jedoch alle Arbeitsdateien unverändert
  2. Verwirft alle Änderungen der Arbeitsdatei und macht den Arbeitsbaum master genau mit dem Status HEAD ~ 3 gleich
  3. Wechselt zu einem vorhandenen Zweig newbranch
  4. Wendet die gespeicherten Änderungen in Ihrem Arbeitsverzeichnis an und löscht den Stapel

Sie können nun git add und git commit wie gewohnt verwenden. Alle neuen Commits werden zu newbranch hinzugefügt. 

Was macht das nicht?

  • Es hinterlässt keine zufälligen temporären Äste, die Ihren Baum stören
  • Die falschen Commit- und Commit-Nachrichten werden nicht beibehalten. Daher müssen Sie dem neuen Commit eine neue Commit-Nachricht hinzufügen

Tore

Das OP erklärte, es sei das Ziel, "den Meister zurückzubringen, bevor diese Commits gemacht wurden", ohne Änderungen zu verlieren, und diese Lösung tut dies.

Ich mache dies mindestens einmal pro Woche, wenn ich versehentlich neue Zusagen in master statt in develop mache. Normalerweise habe ich nur ein Commit für das Rollback. In diesem Fall ist die Verwendung von git reset HEAD^ in Zeile 1 eine einfachere Methode, um nur ein Commit zurückzusetzen. 

Tun Sie dies nicht, wenn Sie die Änderungen des Masters in den Upstream verschoben haben.

Möglicherweise hat jemand anderes diese Änderungen vorgenommen. Wenn Sie nur Ihren lokalen Master umschreiben, hat dies keine Auswirkungen, wenn er in den Upstream-Modus verschoben wird. Wenn Sie jedoch einen neu geschriebenen Verlauf an die Mitarbeiter weiterleiten, kann dies zu Problemen führen. 

46
Slam

Dies "bewegt" sie nicht im technischen Sinne, aber es hat den gleichen Effekt:

A--B--C  (branch-foo)
 \    ^-- I wanted them here!
  \
   D--E--F--G  (branch-bar)
      ^--^--^-- Opps wrong branch!

While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)

A--B--C  (branch-foo)
 \
  \
   D-(E--F--G) detached
   ^-- (branch-bar)

Switch to branch-foo
$ git cherry-pick E..G

A--B--C--E'--F'--G' (branch-foo)
 \   E--F--G detached (This can be ignored)
  \ /
   D--H--I (branch-bar)

Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:

A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
 \
  \
   D--H--I--J--K--.... (branch-bar)
28
Sukima

Um dies zu tun, ohne die Historie neu zu schreiben (d. H. Wenn Sie die Commits bereits gedrückt haben):

git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>

Beide Äste können dann ohne Kraft geschoben werden!

21
teh_senaus

Hatte gerade diese Situation:

Branch one: A B C D E F     J   L M  
                       \ (Merge)
Branch two:             G I   K     N

Ich führte auf:

git branch newbranch 
git reset --hard HEAD~8 
git checkout newbranch

Ich hatte erwartet, dass ich der HEAD bin, aber L ist es jetzt ...

Um sicher zu sein, an der richtigen Stelle in der Geschichte zu landen, ist es einfacher, mit dem Hash des Commits zu arbeiten

git branch newbranch 
git reset --hard #########
git checkout newbranch
12
Darkglow

1) Erstellen Sie einen neuen Zweig, der alle Ihre Änderungen in new_branch verschiebt.

git checkout -b new_branch

2) Gehen Sie dann zum alten Zweig zurück.

git checkout master

3) Gib Git Rebase 

git rebase -i <short-hash-of-B-commit>

4) Der geöffnete Editor enthält dann die letzten 3 Commit-Informationen.

...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...

5) Ändern Sie pick in drop in allen 3 Commits. Dann speichern und schließen Sie den Editor. 

...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...

6) Nun werden die letzten 3 Commits aus dem aktuellen Zweig entfernt (master). Schieben Sie nun die Verzweigung mit dem Zeichen + vor dem Namen der Verzweigung.

git Push Origin +master
2
rashok

Wie kann ich davon ausgehen

A - B - C - D - E 
                |
                master

dazu?

A - B - C - D - E 
    |           |
    master      newbranch

Mit zwei Befehlen

  • Git Branch -m Master Newbranch

geben

A - B - C - D - E 
                |
                newbranch

und

  • Git Branch Master B

geben

A - B - C - D - E
    |           |
    master      newbranch
1
user3070485

Wenn Sie nur alle Ihre nicht gepushten Commits in einen neuen Zweig verschieben müssen, müssen Sie nur

  1. create a new branch from the current one: git branch new-branch-name

  2. Push Ihr neuer Zweig : git Push Origin new-branch-name

  3. zurücksetzen Ihr alter (aktueller) Zweig zum letzten geschobenen/stabilen Zustand: git reset --hard Origin/old-branch-name

Einige Leute haben auch andere upstreams anstatt Origin, sie sollten geeignete upstream verwenden

Sie können dies tun, ist nur 3 einfachen Schritt, den ich verwendet habe. 

1) Erstellen Sie einen neuen Zweig, in dem Sie Ihre letzte Aktualisierung festlegen möchten. 

git branch <branch name> 

2) Suche nach der letzten Commit-ID für das Commit in einem neuen Zweig. 

git log

3) Kopieren Sie die Commit-ID. Beachten Sie, dass die Liste der zuletzt verwendeten Commits oben aufgeführt wird. so können sie ihre verpflichtung finden. Sie finden das auch per Nachricht. 

git cherry-pick d34bcef232f6c... 

sie können auch eine Reihe von Commits angeben.

git cherry-pick d34bcef...86d2aec

Jetzt ist deine Arbeit erledigt. Wenn Sie die richtige ID und den richtigen Zweig ausgewählt haben, werden Sie Erfolg haben. Also, bevor dies geschieht, sei vorsichtig. Andernfalls kann ein anderes Problem auftreten. 

Jetzt können Sie Ihren Code drücken 

git Push

0
Pankaj Kumar