427 Stimmen

Wie kann ich den Inhalt eines Branches in einen neuen lokalen Branch kopieren?

Ich habe an einem lokalen Zweig gearbeitet und die Änderungen auch in den Remote-Zweig übertragen.

Ich möchte die Änderungen in diesem Zweig rückgängig machen und etwas anderes damit tun, aber ich möchte die Arbeit nicht komplett verlieren. Ich dachte an etwas Ähnliches wie das Erstellen eines neuen Zweigs lokalen und das Kopieren des alten Zweigs dorthin. Dann kann ich die Änderungen rückgängig machen und weiter an dem alten Zweig arbeiten.

Gibt es vielleicht eine bessere Möglichkeit als diese?

660voto

Daniel Hilgarth Punkte 165768
git checkout old_branch
git branch new_branch

Dies gibt Ihnen einen neuen Zweig "new_branch" mit dem gleichen Zustand wie "old_branch".

Dieser Befehl kann wie folgt kombiniert werden:

git checkout -b new_branch old_branch

109voto

VonC Punkte 1117238

Siehe zweiter Teil (seit Git 2.23, Q3 2019): git switch -c newBranch oldBranch


Mit Git 2.15 (Q4 2017) lernte "git branch" "-c/-C", um einen neuen Branch durch Kopieren eines vorhandenen zu erstellen.

Siehe commit c8b2cec (18. Jun 2017) von Ævar Arnfjörð Bjarmason (avar).
Siehe commit 52d59cc, commit 5463caa (18. Jun 2017) von Sahil Dua (sahildua2305).
(Merged von Junio C Hamano -- gitster -- in commit 3b48045, 03. Okt 2017)

branch: fügt eine --copy (-c) Option hinzu, um mit --move (-m) zu verwenden

Fügt die Möglichkeit hinzu, einen Branch und dessen Reflog und Konfiguration zu kopieren. Dies verwendet die gleiche zugrunde liegende Mechanik wie die Option --move (-m), außer dass die Reflog und Konfiguration kopiert anstatt verschoben werden.

Dies ist nützlich z. B. zum Kopieren eines Themen-Branches auf eine neue Version, z.B. von work nach work-2 nachdem das Thema work an die Liste gesendet wurde, dabei alle Tracking-Informationen und andere Konfigurationen des Branches beibehaltend und im Gegensatz zu --move den bereits eingereichten anderen Branch als Referenz beibehaltend.

Hinweis: Beim Kopieren eines Branches bleiben Sie auf Ihrem aktuellen Branch.
Wie Junio C Hamano erklärt, war die ursprüngliche Implementierung dieses neuen Features das Ändern von HEAD, was nicht gut war:

Beim Erstellen eines neuen Branches B, indem der Branch A kopiert wird, der zufällig der aktuelle Branch ist, wird auch HEAD aktualisiert, um auf den neuen Branch zu zeigen.
Es wurde wahrscheinlich auf diese Weise gemacht, weil "git branch -c A B" seine Implementierung von "git branch -m A B" abgeleitet hat.

Dies entspricht nicht den üblichen Erwartungen.
Wenn ich auf einem blauen Stuhl sitze und jemand kommt und ihn rot streicht, würde ich akzeptieren, auf einem Stuhl zu sitzen, der jetzt rot ist (ich bin auch damit einverstanden, stattdessen zu stehen, da es meinen Lieblingsblauen Stuhl nicht mehr gibt).

Aber wenn jemand einen neuen roten Stuhl erschafft, ihn modelliert nach dem blauen Stuhl, auf dem ich sitze, erwarte ich nicht, vom blauen Stuhl geworfen zu werden und auf dem neuen roten zu sitzen.


Zweiter Teil: mit Git 2.23 (Q3 2019) müssen Sie weder git branch noch das alte verwirrende git checkout verwenden: Sie haben git switch.

git switch -c newBranch oldBranch

Mit Git 2.40 (Q1 2023), 'git branch -c'(man) ist robuster und erkennt einen no-op-Fall.

Siehe commit cfbd173 (17. Nov 2022) von Rubén Justo (rjusto).
(Merged von Junio C Hamano -- gitster -- in commit 963f8d3, 19. Dez 2022)

branch: Erzwingen des Kopierens eines Branches auf sich selbst über @{-1} ist ein no-op

Unterzeichnet von: Rubén Justo
Unterzeichnet von: Taylor Blau

Seit 52d59cc ("branch: fügt eine --copy (-c) Option hinzu, um mit --move (-m) zu verwenden", 18. Jun 2017, Git v2.15.0-rc0 -- merge in batch #12) können wir einen Branch kopieren, um einen neuen Branch mit der '-c' (Kopieren) Option zu erstellen oder einen vorhandenen Branch mit der '-C' (Erzwinge Kopie) Option zu überschreiben.
Es wird eine no-op-Möglichkeit in Betracht gezogen, wenn wir aufgefordert werden, einen Branch auf sich selbst zu kopieren, um der gleichen no-op-Funktionalität zu folgen, die für die Umbenennungsoperation (-M) in 3f59481 ("branch: Erlaube ein no-op, 25. Nov 2011, Git v1.7.9-rc0 -- merge") (branch: Erlaube ein no-op "branch -M HEAD", 25. Nov 2011).
Um dies zu überprüfen, haben wir in 52d59cc die vom Benutzer bereitgestellten Branch-Namen, Quelle (HEAD, wenn ausgelassen) und Ziel verglichen, und eine Übereinstimmung wird als dieser no-op betrachtet.

Seit ae5a6c3 (checkout: implementieren, 17. Jan 2009, Git v1.6.2-rc0 -- merge) (checkout: implement "@{-N}"-Kurzname für N-ten letzten Branch, 17. Jan 2009) kann ein Branch mit Verknüpfungen wie @{-1} angegeben werden.
Dies ermöglicht diese Verwendung:

$ git checkout -b test
$ git checkout -
$ git branch -C test test  # no-op
$ git branch -C test @{-1} # oops
$ git branch -C @{-1} test # oops

Da wir den vom Benutzer bereitgestellten Branch-Namen für den Vergleich verwenden, wenn einer der Branches über eine Verknüpfung bereitgestellt wird, werden wir keine Übereinstimmung haben und ein Aufruf von git_config_copy_section() wird stattfinden.
Dies wird eine Kopie der Konfiguration für diesen Branch erstellen, und mit diesem Fortschritt wird der zweite Aufruf vier Kopien der Konfiguration erzeugen, und so weiter.

Lassen Sie uns den interpretierten Branch-Namen anstelle davon für diesen Vergleich verwenden.

Die Umbenennungsoperation ist nicht betroffen.

71voto

Lyle Z Punkte 1203
git branch copyOfMyBranch MeineBranch

Dies vermeidet möglicherweise zeitaufwändiges und unnötiges Auschecken eines Zweigs. Denken Sie daran, dass ein Auschecken den "Arbeitsbaum" verändert, was bei großen Dateien oder großen Dateien (Bilder oder Videos beispielsweise) lange dauern könnte.

0voto

Scott Anderson Punkte 572

Angesichts Ihrer Anfrage nach besseren Optionsmöglichkeiten:

Ein potenzieller Nachteil beim Kopieren von Branches besteht darin, dass Sie auf das Fast-Forward-Verhalten von Git achten müssen, wenn Sie in denselben Elternbranch zusammenführen oder Änderungen aus der Kopie wieder in den Originalbranch zurückführen möchten.

Beispielsweise, wenn Sie einige Commits im 'original' Branch rückgängig gemacht haben, aber jetzt die zurückgenommenen Änderungen wieder in den Originalbranch einfügen möchten, können Sie den kopierten Branch nicht einfach in den Elternbranch zusammenführen, da Git diese Commits bereits als vorhanden betrachtet (auch wenn sie später rückgängig gemacht wurden).

Vielleicht würde cherry-pick [commit-range] in diesem Kontext funktionieren & kümmert sich nicht um vorhandene Hashes zuckt mit den Schultern

Meiner Meinung nach wäre es jedoch besser, dies auf folgende Weise zu tun.

  1. Erstellen Sie einen neuen Branch vom aktuellen Branch-HEAD aus git branch [archive-branch-name]
  2. Finden Sie den Commit, zu dem Sie zurückkehren möchten, mit git log
  3. Führen Sie git reset --head [commit-hash-from-#2] aus
  4. git push -f origin

Beachten Sie, dass Sie mit dem 'original' Branch beginnen und während der Schritte keine Branches wechseln.

Oder noch einfacher könnten Sie einfach ganz auf das Branching verzichten und einfach die Commits rückgängig machen, die Sie rückgängig machen möchten, und die Rückgängigmachung später rückgängig machen, wenn Sie es müssen

0voto

Guildenstern Punkte 1288

Ich möchte die Änderungen an diesem Zweig rückgängig machen und etwas anderes darauf tun, aber ich möchte die Arbeit nicht komplett verlieren.

Meine Interpretation ist, dass du für den Zweig b folgendes möchtest:

  • Erstelle eine Kopie kopie-b (sagen wir) für zukünftige Referenzen
  • Arbeite weiter an b, wissend dass du kopie-b für zukünftige Referenzen hast

Es scheint impliziert zu sein, dass kopie-b in Ruhe gelassen wird; es ist nur für Referenzen.

Also wofür brauchst du einen Zweig? Ein Zweig muss sich bewegen können, während eine "zur Referenz" Ref das nicht kann. Brauchst du das Reflog? Nun, das läuft standardmäßig nach 90 Tagen ab, also spielt das langfristig keine Rolle. Vielleicht möchtest du die Beschreibung des Zweigs oder eine andere Konfiguration?

Wenn du nur kopieren möchtest, wohin das Ref zeigt, dann benötigst du nur ein leichtgewichtiges Tag:

git checkout b
git tag archiv/b

Oder mit git switch:

git switch b
git tag archiv/b

Und wenn du mehrere Versionen hast:

git tag archiv/b-v1

Dieses Schema kann verwendet werden, wenn man eine "Patch-Serie" per E-Mail verschickt, die durch mehrere Runden überprüft wird.

Einige offensichtliche Vorteile dieses Schemas:

  1. Könnte etwas einfacher sein, solche "zur Referenz" Refs mit git-clone(1) einzuschließen oder auszuschließen (mit --tags oder --no-tags)
  2. Du wirst sie nicht versehentlich auschecken und an ihnen arbeiten (nun ja, du bekommst eine "detached head" Warnung/Notiz, wenn du es dennoch tust)
  3. Zweige werden standardmäßig nicht komprimiert mit git-pack-refs(1), während Tags das sind (ich nehme an, man müsste ein wirklich engagierter Archivar sein, damit das eine Rolle spielt, aber...)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X