Nicht festgeschriebene Änderungen in Subversion vorübergehend weglegen (a la "git-stash")


312

Während ich in einem Subversion-Repo gespeicherte Programmiersoftware programmiere, ändere ich häufig einige Dateien und stelle dann fest, dass ich einige vorbereitende Änderungen für meine Hauptarbeit vornehmen möchte. Während ich beispielsweise neue Funktionen implementiere, bemerke ich einige Umgestaltungen, die mir helfen könnten.

Um zwei nicht zusammenhängende Änderungen nicht zu mischen, möchte ich in diesen Fällen meine Änderungen "verstauen", dh zur Repository-Version zurückkehren, einige andere Änderungen vornehmen, diese festschreiben und dann meine Änderungen "zurückholen".

git-stash ermöglicht genau das. Gibt es eine Möglichkeit, dies mit Subversion entweder direkt oder mit einem Plugin oder Skript zu tun? Eclipse-Plugins wären auch in Ordnung.


6
nur neugierig, aber warum nicht git-svn verwenden?
cmcginty

3
Einige relevante Neuigkeiten: infoworld.com/d/application-development/… (zitiert: "Er merkt auch an, dass die kommende Version von Subversion 1.8 die Funktionen von Git näher bringen sollte, mit Funktionen wie Git Stash, in denen ein Entwickler lokal Änderungen vornehmen kann und legen Sie sie dann beiseite, und Offline-Commits, die abgeschlossene Änderungen aufzeichnen, wenn ein Entwickler offline ist, und die in das Master-Repository verschieben, wenn der Entwickler die Verbindung wieder herstellt. "
Sebastiaan van den Broek

1
Update (Stand 26.04.2012): Die Regale sind jetzt für 1.9 ohne ETA geplant. So kann es eine Weile dauern ...
Sleske

10
Update (Stand 17.11.2012): Die Regale sind jetzt für 1.10 geplant. Vielleicht ist es immer für <nächste Version +1> geplant? ;-)
Sleske

3
Update (Stand 23.03.2015, zweieinhalb Jahre später): Eine gute Nachricht ist, dass die Regale noch für 1.10 geplant sind. Schlechte Nachrichten sind die ETA: Q2 2015 (vorläufig) Release 1.9.0 / 2017? (bestenfalls spekulativ) Release 1.10.0 ( subversion.apache.org/roadmap.html )
Ribamar

Antworten:


69

Wenn ich nicht festgeschriebene Änderungen von einer Aufgabe in meiner Arbeitskopie habe und zu einer anderen Aufgabe wechseln muss, mache ich eines von zwei Dingen:

  1. Überprüfen Sie eine neue Arbeitskopie für die zweite Aufgabe.

    oder

  2. Starten Sie einen Zweig:

    workingcopy$ svn copy CURRENT_URL_OF_WORKING_COPY SOME_BRANCH
    workingcopy$ svn switch SOME_BRANCH
    workingcopy$ svn commit -m "work in progress"
    workingcoyp$ svn switch WHATEVER_I_WAS_WORKING_ON_BEFORE
    

Ich habe einige Skripte, die helfen, dies zu automatisieren.


65
Dies wird zu viel Müll auf Ihrem Subversion-Server führen
knittl

3
@knittl: Nein, das wird es nicht. Und was noch wichtiger ist: Es geht nicht zu Änderungen, die verloren gehen, ebenso wie Ihr Vorschlag. Dies und eine weitere ausgecheckte Kopie des Trunks / des gleichen Zweigs sind die einzigen zwei zuverlässigen Möglichkeiten, dies zu tun, die ich kenne. Wenn Sie sich damit unwohl fühlen, schauen Sie sich einfach eine andere Kopie an und arbeiten Sie parallel daran.
sbi

2
@knittl: Der Zweig kann in einem unauffälligen Pfad erstellt werden, der außerhalb des Standardorts für Zweige oder Tags des Projekts liegt. Zum Beispiel kann ein Team project\temp\<creationdate-reason>oder project\personal\<creationdate-reason>zu diesem Zweck bestimmen.
Rwong

12
Es ist immer noch bedauerlich, dass der Zweig überhaupt auf dem Server erstellt werden muss. Es ist nicht so, dass solche Zweige viele Daten duplizieren, sondern dass sie viele unnötige Referenzen erstellen, auf die ein System wie git verzichtet.
Thepeer

8
Dies ist bei einem großen Repository nicht sinnvoll. Dies ist in meiner Arbeitsumgebung absolut keine Option. Und obwohl ich mir wünschte, unser Repository wäre kleiner und besser organisiert, und ehrlich gesagt, ein Git-Repository anstelle von SVN, beschränke ich mich auf die Grenzen der Organisation unseres Codes in unserer Organisation.
AdrianVeidt

337

Dieser Blog-Beitrag empfiehlt die Verwendung von Diff und Patch.

  • git stash ungefähr wird svn diff > patch_name.patch; svn revert -R .
  • git stash apply wird patch -p0 < patch_name.patch

Beachten Sie, dass hierdurch keine Metadatenänderungen gespeichert oder (glaube ich) Verzeichnisse erstellt / gelöscht werden. (Ja, svn verfolgt diese im Gegensatz zu git getrennt vom Verzeichnisinhalt.)


13
Dies ist ein versehentliches Duplikat von stackoverflow.com/questions/1554278/… - senden Sie dort Upvotes.
Walter Mundt

2
Es scheint auch keine Binärdateien zu enthalten, was ärgerlich ist. Zumindest bei Verwendung von TortoiseSVN zum Generieren des Patches.
Angularsen


6
Sie können die Metadaten mehr oder weniger nachverfolgen lassen, wenn Sie sie svn patch patch_name.patchanstelle von verwenden patch -p0, da sie in der Patch-Datei enthalten sind und der SVN-Patch sie versteht.
Mat

Dies beinhaltet keine Änderungen an externen Geräten.
Congusbongus

182

Sie können Ihre aktuellen Änderungen mit svn diffin einer Patch-Datei speichern und dann Ihre Arbeitskopie zurücksetzen:

svn diff > stash.patch
svn revert -R .

Nachdem Sie Ihre vorbereitende Funktion implementiert haben, können Sie Ihren Patch mit dem Patch-Dienstprogramm anwenden:

patch < stash.patch

Wie andere angemerkt haben, funktioniert dies nicht mit svn:propertiesBaumoperationen (Hinzufügen, Entfernen, Umbenennen von Dateien und Verzeichnissen).

Binärdateien könnten auch Probleme verursachen, ich weiß nicht, wie Patch (oder TortoiseSVN in diesem Fall behandelt sie).


4
Dies funktioniert wahrscheinlich nicht gut mit entfernten / umbenannten Dateien, denke ich.
JesperE

7
Siehe das Feld mit dem Titel "Warum nicht stattdessen Patches verwenden?" unter svnbook.red-bean.com/de/1.5/… um zu verstehen, warum dies eine schlechte Idee ist.
sbi

4
@sbi: Ich denke nicht, dass dies eine gültige Rechtfertigung für eine Ablehnung ist. Es ist keine "schlechte Antwort". Es ist einfach nicht die perfekte Antwort, die alles ist. Ich denke nicht, dass diese Person eine Bestrafung für ihren Vorschlag verdient. Möchten Sie, dass er nicht antwortet? Wenn ja, dann ja, sollten Sie abstimmen. Ansonsten bestraft dies gute Absichten.
Sedat Kapanoglu

5
Für den Fall, dass jemand wie ich der Meinung ist, dass dies die leichteste Lösung ist, und beschließt, es zu versuchen, musste ich patch -p0 <stash.patch verwenden. Andernfalls wurde beschwert, dass die zu
patchenden

4
Dieser Rat hilft besonders, wenn Sie aus einem Git-Hintergrund kommen und aus verschiedenen Gründen gezwungen sind, SVN zu verwenden. Eine kleine Verbesserung der Ratschläge, die bereits für Erstbenutzer von Patches gegeben wurden: $ patch --strip=0 < stash.patch Dadurch wird sichergestellt, dass der Patch Sie beim Anwenden Ihres Patches nicht nach dem Dateinamen fragt.
Ksinkar

43

Der einfachste Weg wäre, einen temporären Zweig wie diesen zu verwenden:

$ svn copy ^/trunk ^/branches/tempbranch
$ svn switch ^/branches/tempbranch
$ svn commit -m "Stashed"
$ svn switch ^/trunk
$ ... hack away in trunk ...
$ svn commit -m "..."
$ svn merge ^/branches/tempbranch .
$ svn rm ^/branches/tempbranch
$ ... continue hacking

Dies könnte (und sollte wahrscheinlich) in ein Skript eingefügt werden, wenn es regelmäßiger durchgeführt wird.


2
Warum wird dies abgelehnt, während "Lösungen" abgelehnt werden, die nicht einmal funktionieren, wenn Sie Dateien gelöscht / hinzugefügt oder Eigenschaften geändert haben? Ja, dies ist nicht die einfachste Sache, wenn Sie es zum ersten Mal tun, aber abgesehen davon, dass eine andere Kopie ausgecheckt wurde, um parallel zu arbeiten, ist dies die einzige Lösung, die in allen Fällen funktioniert.
sbi

5
Gute Verwendung der ^ -Syntax für Repo-Root (seit SVN 1.6). Gute Lösung, wenn Ihr Repo Trunk / Tags / Zweige auf oberster Ebene hat.
Bendin

4
Ich mag es nicht wirklich, all diese temporären Zweige auf den Server zu stellen. Ich bin der Meinung, dass dies lokal erfolgen sollte, anstatt den Server zu überladen (und Spurios-Check-in-E-Mails zu generieren, wenn Sie beim Check-in E-Mails generieren). Dennoch eine Option, an die man sich erinnern sollte.
Sleske

3
@sleske: Ja, Sie übergeben Ihren temporären Stash an den Server, aber der Zweig selbst wird gelöscht. Ich denke jedenfalls, dass dies der schnellste und robusteste Weg ist, dies zu tun.
JesperE

5
@sleske: SVN ist kein verteiltes VCS, daher muss sich alles auf dem Server befinden. So ist es halt.
sbi

24

Ab 1.10.0 (2018-04-13) haben Sie einen experimentellen svn shelveBefehl . ( TortoiseSVN unterstützt den Befehl ) Es ist nichts anderes als ein Helfer, um einen Patch zu speichern und wieder anzuwenden, daher gibt es dieselben Einschränkungen wie svn diff+ patch(dh es können keine Binärdateien verarbeitet und umbenannt werden). ( Bearbeiten : Es sieht so aus, als ob die nächste Version 1.11.0 Binärunterstützung bietet. )

Bearbeiten ^ 2: Mit 1.11.0 (veröffentlicht am 30.10.2018) werden Binärdateien unterstützt . Das Umbenennen umbenannter Dateien wurde nicht unterstützt. Regale in 1.11 sind nicht kompatibel mit Regalen, die mit 1.10 erstellt wurden.

Bearbeiten ^ 3: Mit 1.12.0 (veröffentlicht am 24.04.2019) werden Kopieren und Umbenennen unterstützt . Regale in 1.12 sind nicht kompatibel mit Regalen, die von früheren Versionen erstellt wurden.

Bearbeiten ^ 4: Mit 1.13.0 und 1.14.0 gibt es keine Änderung in Bezug auf Regale . Befehle sind weiterhin als experimentell markiert und müssen definiert werden SVN_EXPERIMENTAL_COMMANDS=shelf3, um die Funktion zu aktivieren. Es sieht so aus, als ob die Funktion derzeit nicht getestet wurde .

Design-Hinweise finden Sie im Entwickler- Wiki .

$ svn x-shelve --help
x-shelve: Move local changes onto a shelf.
usage: x-shelve [--keep-local] SHELF [PATH...]

  Save the local changes in the given PATHs to a new or existing SHELF.
  Revert those changes from the WC unless '--keep-local' is given.
  The shelf's log message can be set with -m, -F, etc.

  'svn shelve --keep-local' is the same as 'svn shelf-save'.

  The kinds of change you can shelve are committable changes to files and
  properties, except the following kinds which are not yet supported:
     * copies and moves
     * mkdir and rmdir
  Uncommittable states such as conflicts, unversioned and missing cannot
  be shelved.

  To bring back shelved changes, use 'svn unshelve SHELF'.

  Shelves are currently stored under <WC>/.svn/experimental/shelves/ .
  (In Subversion 1.10, shelves were stored under <WC>/.svn/shelves/ as
  patch files. To recover a shelf created by 1.10, either use a 1.10
  client to find and unshelve it, or find the patch file and use any
  1.10 or later 'svn patch' to apply it.)

  The shelving feature is EXPERIMENTAL. This command is likely to change
  in the next release, and there is no promise of backward compatibility.

Valid options:
  -q [--quiet]             : print nothing, or only summary information
  --dry-run                : try operation but make no changes
  --keep-local             : keep path in working copy

(...)

$ svn x-unshelve --help
x-unshelve: Copy shelved changes back into the WC.
usage: x-unshelve [--drop] [SHELF [VERSION]]

  Apply the changes stored in SHELF to the working copy.
  SHELF defaults to the newest shelf.

  Apply the newest version of the shelf, by default. If VERSION is
  specified, apply that version and discard all versions newer than that.
  In any case, retain the unshelved version and versions older than that
  (unless --drop is specified).

  With --drop, delete the entire shelf (like 'svn shelf-drop') after
  successfully unshelving with no conflicts.

  The working files involved should be in a clean, unmodified state
  before using this command. To roll back to an older version of the
  shelf, first ensure any current working changes are removed, such as
  by shelving or reverting them, and then unshelve the desired version.

  Unshelve normally refuses to apply any changes if any path involved is
  already modified (or has any other abnormal status) in the WC. With
  --force, it does not check and may error out and/or produce partial or
  unexpected results.

  The shelving feature is EXPERIMENTAL. This command is likely to change
  in the next release, and there is no promise of backward compatibility.

Valid options:
  --drop                   : drop shelf after successful unshelve
(...)

$ svn help | grep x-
 x-shelf-diff
 x-shelf-drop
 x-shelf-list (x-shelves)
 x-shelf-list-by-paths
 x-shelf-log
 x-shelf-save
 x-shelve
 x-unshelve

9

Ich kenne keinen einfachen Weg, dies mit nur svn zu tun. Ehrlich gesagt würde ich empfehlen git-svn, ein Git-Repo zu erstellen, das als SVN-Arbeitskopie fungiert, und nur damit zu verwenden git stash. Ersetzen Sie einfach git pullmit git svn rebaseund git pushmit git svn dcommitund Sie können tatsächlich halten 90% der git Workflow und immer noch zu einem SVN - Server sprechen.


Aber der Link stackoverflow.com/questions/1554278/…, den ich in den obigen Kommentaren erwähne, schlägt eine praktische Lösung vor, um nur einen Stash in svn zu machen.
VonC

Meinetwegen; Tatsächlich hat mich Google gerade in einem Blog zu dieser Lösung geführt. Ich behaupte immer noch, dass git-svn für diesen Fragesteller eine natürliche Lösung ist.
Walter Mundt

Ich bezweifle, dass die Lösung den Umbenennungen der Datei folgt, da Git dies nicht tut.
NO_NAME

4

svn-stashUnter GPL 3 ist ein kleines Python 2-Skript namens https://github.com/frankcortes/svn-stash verfügbar .

Es funktioniert wie die svn diff/patchgenannten Lösungen und bietet das Verschieben und Löschen von Änderungen, wenn sie sich in einem lokalen Verzeichnis unterscheiden. Leider können die Verstecke nicht benannt werden und nur der letzte kann geknallt werden (nun ja, es ist ein Stapel, aber es gibt keinen wirklichen Grund für eine solche Einschränkung.) Aber dann könnten Sie immer die fehlenden Funktionen in die einbauen Quelle.

Es ist für * ix geschrieben, aber nach dem Ersetzen jedes "/" os.sepfunktioniert es auch unter Windows gut.

Wenn Sie svn 1.7 oder höher verwenden, müssen Sie Folgendes ändern is_a_current_stash(): Entfernen Sie die Zeile if ".svn" in os.listdir(CURRENT_DIR):, da in 1.7-WCs nur ein .svn-Unterverzeichnis der obersten Ebene vorhanden ist.


Es ist nicht für mich unter Fenstern! :(
Antonio Petricca

4

Mit Intellij IDEA - Shelve Changes können Sie dies ganz einfach tun


Kann dieser Weg mit metadata changesund umgehen directory creates/deletes? Wie genau was git stashmacht?
Wonsuc

3

Eine andere Möglichkeit besteht darin, Ihre aktuelle Kasse in ein neues Verzeichnis zu kopieren und alle Ihre Änderungen zurückzusetzen. Auf diese Weise ersparen Sie sich den Aufwand, einen temporären Zweig auf Ihrem Server zu erstellen - schließlich ist das Verstecken eine lokale Operation, die nicht jeder sehen sollte und die ziemlich oft ausgeführt werden kann.

Nach dem Festschreiben Ihres Hotfixes können Sie Ihre Hauptarbeitskopie aktualisieren und Ihren "Versteckbereich" löschen.


Hinweis: Das entspricht im Wesentlichen dem Auschecken einer zweiten Arbeitskopie - nur ohne Auschecken :-).
Sleske

6
@sleske: Ja, ohne die enorme Menge an Bandbreite, die für eine neue
Kaufabwicklung

Ob es Ihnen gefällt oder nicht, dies ist die Antwort, die das Verhalten von "git stash" genauer widerspiegelt. Das Erstellen eines Zweigs ist cool, hängt jedoch eher mit TFS-Regalen zusammen.
Charles Roberto Canato

1

Ich wollte auch diese Funktion. Ich benutze derzeit TortoiseSVN.

Ich habe keine feste Lösung gefunden, außer den Baum zu exportieren, zum Repository zurückzukehren, meine Änderungen vorzunehmen und festzuschreiben und dann die Änderungen aus dem exportierten Baum mit einem Tool wie Beyond Compare wieder in mein quellgesteuertes Verzeichnis zu vergleichen.

Eine andere Lösung könnte darin bestehen, vom HEAD in ein anderes Verzeichnis zu verzweigen, Ihre Änderungen vorzunehmen und das Commit durchzuführen. Wenn Sie bereit sind, diese wieder mit Ihrer anderen Arbeitskopie zusammenzuführen, führen Sie ein Update durch und führen Sie Ihre Änderungen zusammen.


1

Ich behalte immer eine zweite Kasse, die ich "trunk_clean" nenne. Wann immer ich eine schnelle, isolierte Änderung in Bezug auf das, was ich tue, vornehmen muss, verpflichte ich mich stattdessen nur zu dieser Kasse.


0

Die obigen Verzweigungs- und Patching-Ideen sind großartig, aber sie funktionieren für mich nicht gut. Ich verwende ein visuelles Diff-Tool, sodass beim Ausführen git diffkeine textbasierten Patches erzeugt werden. Unser Build-System startet jedes Mal, wenn ein Zweig erstellt wird, eine neue Umgebung, sodass das Erstellen temporärer "Stash" -Zweige unübersichtlich wird.

Stattdessen habe ich ein kleines Shell-Skript geschrieben , das eine Datei in ein "Regal" -Verzeichnis kopiert, einen Zeitstempel hinzufügt und die Änderung zurücksetzt. Es ist nicht so robust wie die oben genannten Lösungen, aber es vermeidet auch einige der Fallstricke, auf die ich gestoßen bin.


0

Basierend auf der Antwort von Walter habe ich die folgenden Aliase in meiner bashrc-Datei erstellt:

alias svn.stash='read -p "saving local changes in raq.patch. Existing stash in raq.patch will be overwritten. Continue?[y/N]" && [[ $REPLY =~ ^[yY] ]] && rm -f raq.patch && svn diff > raq.patch && svn revert -R .'
alias svn.stash.apply='patch -p0 < raq.patch; rm -f raq.patch'

Diese Aliase sind viel einfacher zu verwenden und zu merken.

Verwendungszweck:

svn.stash , um Änderungen zu speichern , und svn.stash.apply , um Stash anzuwenden.


0

In meiner Praxis git initerstelle ich ein Git-Repository im trunkVerzeichnis meines Subversion-Repositorys und füge *.gitdann den Suctions-Ignoriermustern hinzu.

Wenn ich nach dem Ändern einiger Dateien meine Arbeit mit der Subversion-Hauptzeile fortsetzen möchte, verwende ich sie nur git stashzum Verstecken meiner Arbeit. Nach dem Festschreiben im Subversion-Repository git stash popstelle ich meine Änderungen wieder her.


2
Das ist eigentlich eine gute Lösung! Viele andere Lösungen verwenden Tools von Drittanbietern, um das Problem zu lösen. Dieser verwendet Git als Tool von Drittanbietern. Dies hat mehrere Vorteile: 1) Git ist sehr allgemein und leistungsfähig. 2) Viele Leute haben Git bereits installiert.
Lii

Ich bin gespannt, wie das funktioniert, wenn Sie nicht auch ein Git-Commit machen.
B2K

0

Verwenden:

svn cp --parents . ^/trash-stash/my-stash

Es wird ein Zweig aus dem aktuellen Speicherort und der aktuellen Revision erstellt und anschließend die Änderungen in der Arbeitskopie in diesen Zweig übernommen, ohne zu diesem zu wechseln.

Verwendung: Kopieren Sie SRC [@REV] ... DST

SRC und DST können jeweils ein Arbeitskopiepfad (WC) oder eine URL sein:

WC  -> URL:  immediately commit a copy of WC to URL

Beachten Sie, dass Änderungen in der Arbeitskopie nicht automatisch zurückgesetzt werden ( cpnur das Kopieren von Änderungen in einen neuen Zweig) und Sie sie manuell zurücksetzen müssen.

Um die Änderungen wiederherzustellen, können Sie die Änderungen aus dem neu erstellten Zweig einfach mit Ihrer Arbeitskopie zusammenführen.

svn merge --ignore-ancestry ^/trash-stash/my-stash -c <commited revision>

--ignore-ancestry wird verwendet, um die Zusammenführungsinformationen in der Arbeitskopie nicht zu aktualisieren.

Verwenden:

svn ls -v ^/trash-stash/

um zu sehen, was Sie auf dem Versteckweg haben. Festgeschriebene Revisionen werden ebenfalls gedruckt.

Wenn Sie das Versteck nicht mehr benötigen, führen Sie einfach Folgendes aus:

svn rm ^/trash-stash/my-stash

Diese Lösung ist insofern besser als die Verwendung von Patches, als wenn neue Änderungen in der Arbeitskopie oder im aktuellen Zweig mit den Änderungen im Stash in Konflikt stehen, Sie die Konflikte mit svn-Mitteln lösen können, während patchPatches in einigen Fällen einfach fehlschlagen oder sogar falsch angewendet werden .


-1

Da Subversion die Funktion nicht stashperfekt unterstützt,
mache ich einfach so manuell.

Platzieren Developmentund Production(release)auf einen getrennten Pfad projizieren.

source\code\MyApp         -- Development
release\MyApp(release)    -- Production(release)

Sie können alle neuen Funktionen für Ihr Projekt im Entwicklungspfad bearbeiten,
und Sie würden nur bedeutende Fortschritte erzielen, oder es sollte etwas für den Stall freigegeben werden.

Wenn Sie es für die Produktion freigeben müssen, öffnen Sie das Produktionsprojekt, aktualisieren Sie svn und erledigen Sie die Freigabe (Erstellen, Exportieren usw.).

Ich weiß, dass dies ein bisschen mühsam ist, aber das Freigeben von Fortschritten kommt nicht oft vor (es ist nicht für mich, aber ich weiß, dass einige Projekte dies tun), verglichen mit dem Entwickeln von Fortschritten. Dieser Weg passt zu mir.

Ich benutze svn für bestimmte Projekte, da die Mitglieder des Projektteams es verwenden, also muss ich folgen.
Die beste Lösung ist die Verwendung giteines perfekten Versionskontrollsystems und besser als svn.


Es ist nicht ganz klar, was Sie tun (welche Version ist in den von Ihnen erwähnten Verzeichnissen ausgecheckt?), Aber es sieht aus wie ein Duplikat der am besten bewerteten Antwort ("Eine neue Arbeitskopie auschecken").
Sleske

@sleske Entschuldigung, ich habe Ihre Falldetails nicht gelesen. In meinem Fall brauche ich nur devund prod, 2 Situationen. Die Entwicklung völlig neuer Funktionen wäre mit svn kompliziert. Ich bin mir nicht sicher, ob es eine klare Methode gibt, um Ihren Fall in der SVN-Welt zu lösen.
Wonsuc
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.