Supprimez temporairement les modifications non validées de Subversion (à la «git-stash»)

312

Lors de la programmation d'un logiciel stocké dans un dépôt Subversion, je modifie souvent certains fichiers, puis je remarque que j'aimerais effectuer des changements préparatoires pour mon travail principal. Par exemple, lors de la mise en œuvre de nouvelles fonctionnalités, je remarque une refactorisation qui pourrait m'aider.

Afin de ne pas mélanger deux modifications non liées, dans ces cas, je voudrais "ranger" mes modifications, c'est-à-dire revenir à la version du référentiel, effectuer d'autres modifications, les valider, puis "récupérer" mes modifications.

git-stash permet de faire exactement cela. Existe-t-il un moyen de le faire avec Subversion, soit directement, soit avec un plugin ou un script. Les plugins Eclipse seraient également très bien.

sleske
la source
6
juste curieux, mais pourquoi ne pas utiliser git-svn?
cmcginty
3
Quelques nouvelles pertinentes: infoworld.com/d/application-development/… (citant: "Il note également que la prochaine version de Subversion 1.8 devrait la rapprocher des capacités de Git, avec des fonctionnalités comme Git stash, dans lesquelles un développeur peut apporter des modifications localement puis les mettre de côté et les validations hors ligne, qui enregistrent les modifications terminées lorsqu'un développeur est hors ligne et les déplace vers le référentiel maître lorsque le développeur se reconnecte. "
Sebastiaan van den Broek
1
Mise à jour (à partir du 2012-04-26): Le rayonnage est désormais prévu pour 1.9, sans ETA. Cela peut donc prendre un certain temps ...
sleske
10
Mise à jour (à partir du 2012-11-17): des étagères sont maintenant prévues pour 1.10. Peut-être est-il toujours prévu pour la <prochaine version +1>? ;-)
sleske
3
Mise à jour (à partir du 2015-03-23, 2 ans et demi plus tard): La bonne nouvelle est que le rayonnage est toujours prévu pour 1.10. Les mauvaises nouvelles sont l'ETA: T2 2015 (provisoire) version 1.9.0 / 2017? (spéculative au mieux) Version 1.10.0 ( subversion.apache.org/roadmap.html )
ribamar

Réponses:

69

Lorsque j'ai des modifications non validées d'une tâche dans ma copie de travail et que je dois passer à une autre tâche, je fais l'une des deux choses suivantes:

  1. Découvrez une nouvelle copie de travail pour la deuxième tâche.

    ou

  2. Démarrer une succursale:

    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
    

J'ai quelques scripts qui aident à automatiser cela.

bendin
la source
65
cela se traduira par beaucoup de déchets sur votre serveur subversion
knittl
3
@knittl: Non, ce ne sera pas le cas. Et ce qui est encore plus important: cela n'entraînera pas la perte des modifications comme le fait votre suggestion. Ceci, et avoir une autre copie extraite de la branche / même branche, sont les deux seuls moyens fiables de le faire que je connaisse. Si cela vous met mal à l'aise, vérifiez simplement une autre copie et travaillez-la en parallèle.
sbi
2
@knittl: la branche peut être créée dans un chemin discret qui se trouve en dehors de l'emplacement par défaut des branches ou des balises du projet. Par exemple, une équipe peut désigner project\temp\<creationdate-reason>ou project\personal\<creationdate-reason>à cette fin.
rwong
12
Il est toujours regrettable que la branche doive être créée sur le serveur. Ce n'est pas que de telles branches dupliquent beaucoup de données, mais qu'elles créent beaucoup de références inutiles dont un système comme git se passe.
thepeer
8
ce n'est pas utile avec un grand référentiel. Ce n'est absolument pas une option dans mon environnement de travail. Et même si je souhaite que notre référentiel soit plus petit et mieux organisé, et franchement, un référentiel git au lieu de svn, je suis confiné aux limites de l'organisation de notre code dans notre organisation.
AdrianVeidt
337

Ce billet de blog conseille d'utiliser diff et patch.

  • git stash devient approximativement svn diff > patch_name.patch; svn revert -R .
  • git stash apply devient patch -p0 < patch_name.patch

Notez que cela ne cache pas les modifications de métadonnées ou (je pense) que le répertoire crée / supprime. (Oui, svn suit ceux-ci séparément du contenu du répertoire, contrairement à git.)

Walter Mundt
la source
13
Il s'agit d'un doublon accidentel de stackoverflow.com/questions/1554278/… - envoyez-y des votes positifs.
Walter Mundt
2
Il ne semble pas non plus inclure de fichiers binaires, ce qui est ennuyeux. Au moins lors de l'utilisation de TortoiseSVN pour générer le patch.
angularsen
1
stackoverflow.com/questions/159853/… pourrait vous aider.
Walter Mundt
6
Vous pouvez plus ou moins faire suivre les métadonnées si vous utilisez à la svn patch patch_name.patchplace de patch -p0, car elles sont dans le fichier de correctif, et svn patch les comprend.
mat
Cela n'inclut pas les modifications apportées aux éléments externes.
congusbongus
182

Vous pouvez stocker vos modifications actuelles svn diffdans un fichier correctif, puis restaurer votre copie de travail:

svn diff > stash.patch
svn revert -R .

Après avoir implémenté votre fonction préparatoire, vous pouvez ensuite appliquer votre patch avec l'utilitaire de patch:

patch < stash.patch

Comme d'autres l'ont noté, cela ne fonctionnera pas avec svn:propertiesles opérations d'arborescence (ajouter, supprimer, renommer des fichiers et des répertoires).

Les fichiers binaires peuvent également poser des problèmes, je ne sais pas comment le patch (ou TortoiseSVN dans ce cas les gère).

knittl
la source
4
Cela ne fonctionne probablement pas trop bien avec les fichiers supprimés / renommés, je pense.
JesperE
7
Voir l'encadré intitulé "Pourquoi ne pas utiliser de correctifs à la place?" sur svnbook.red-bean.com/en/1.5/… pour comprendre pourquoi c'est une mauvaise idée.
sbi
4
@sbi: Je ne pense pas que ce soit une justification valable pour un downvote. Ce n'est pas une "mauvaise réponse". Ce n'est tout simplement pas la réponse parfaite, c'est tout. Je ne pense pas que cette personne mérite une punition pour sa suggestion. Préférez-vous qu'il ne réponde pas à la place? Si oui, alors oui, vous devriez voter contre. Sinon, cela punit les bonnes intentions.
Sedat Kapanoglu
5
au cas où quelqu'un d'autre, comme moi, penserait que cela ressemble à la solution la plus légère et décide de l'essayer, j'ai dû utiliser le patch -p0 <stash.patch - sinon il s'est plaint de ne pas pouvoir trouver les fichiers à patcher
CupawnTae
4
Ce conseil est particulièrement utile si vous venez d'un arrière-plan git et êtes obligé d'utiliser SVN pour diverses raisons. Une petite amélioration dans les conseils déjà donnés pour les nouveaux utilisateurs de patch: $ patch --strip=0 < stash.patch cela garantira que le patch ne vous demandera pas le nom du fichier lorsque vous appliquez votre patch.
ksinkar
43

La façon la plus simple serait d'utiliser une branche temporaire, comme ceci:

$ 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

Cela pourrait (et devrait probablement) être mis dans un script si cela était fait plus régulièrement.

JesperE
la source
2
Pourquoi est-ce rejeté, alors que des «solutions» sont votées qui ne fonctionnent même pas lorsque vous avez supprimé / ajouté des fichiers ou modifié des propriétés? Oui, ce n'est pas la chose la plus simple à faire lorsque vous le faites pour la première fois, mais, en plus d'avoir une autre copie extraite pour fonctionner en parallèle, c'est la seule solution qui fonctionne dans tous les cas.
sbi
5
Belle utilisation de la syntaxe ^ pour le repo root (depuis svn 1.6). Bonne solution lorsque votre dépôt a un tronc / tags / branches au niveau supérieur.
bendin
4
Je n'aime pas vraiment mettre toutes ces branches temporaires sur le serveur. Je pense que cela devrait être fait localement, au lieu d'encombrer le serveur (et de générer des e-mails de consignation spurios, si vous générez des e-mails à l'enregistrement). Pourtant, une option mérite d'être rappelée.
sleske
3
@sleske: oui, vous validez votre cachette temporaire sur le serveur, mais la branche elle-même est supprimée. Quoi qu'il en soit, je pense que c'est la façon la plus rapide et la plus robuste de le faire.
JesperE
5
@sleske: SVN n'est pas un VCS distribué, donc tout doit être sur le serveur. C'est comme ça.
sbi
24

Depuis la 1.10.0 (13/04/2018), vous disposez d'une svn shelvecommande expérimentale . ( TortoiseSVN prend en charge la commande ) Ce n'est rien d'autre qu'une aide pour enregistrer un patch et le réappliquer, il a donc les mêmes limitations que svn diff+ patch(c'est-à-dire qu'il ne peut pas gérer les fichiers binaires et les renommer). ( Edit : On dirait que le support binaire arrivera à la prochaine version 1.11.0 )

Modifier ^ 2: Avec 1.11.0 (publié le 2018-10-30), les fichiers binaires sont pris en charge . Le stockage des fichiers renommés n'est pas pris en charge. Les étagères en 1.11 sont incompatibles avec les étagères créées par 1.10.

Modifier ^ 3: avec 1.12.0 (publié le 2019-04-24), la copie et le changement de nom sont pris en charge . Les étagères en 1.12 sont incompatibles avec les étagères créées par les versions antérieures.

Edit ^ 4: Il n'y a aucun changement autour des rayonnages avec 1.13.0 et 1.14.0 . Les commandes sont toujours marquées comme expérimentales et vous devez définir SVN_EXPERIMENTAL_COMMANDS=shelf3pour activer la fonctionnalité. Il semble que la fonctionnalité ne soit pas actuellement testée .

Les notes de conception peuvent être trouvées sur le wiki des développeurs .

$ 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
snipsnipsnip
la source
9

Je ne connais pas de moyen facile de le faire avec juste svn. Honnêtement, je vous conseille d'utiliser git-svnpour faire un dépôt git qui agit comme une copie de travail svn, et de simplement l'utiliser git stashavec cela. Remplacez simplement git pullpar git svn rebaseet git pushpar git svn dcommitet vous pouvez réellement conserver 90% de votre flux de travail git et toujours parler à un serveur svn.

Walter Mundt
la source
Mais le lien stackoverflow.com/questions/1554278/… que je mentionne dans les commentaires ci-dessus propose une solution pratique pour faire un stash en svn uniquement.
VonC
C'est suffisant; en fait, google m'a amené à cette solution sur un blog tout à l'heure. Je maintiens toujours que, pour ce questionneur, git-svn est une solution naturelle.
Walter Mundt
Je doute que cette solution suive les noms de fichiers, car git ne le fait pas.
NO_NAME du
4

Il existe un petit script Python 2 appelé svn-stashdisponible sous GPL 3: https://github.com/frankcortes/svn-stash .

Il fonctionne comme les svn diff/patchsolutions mentionnées et offre des poussées et des sauts de modifications sous forme de différences dans un répertoire local. Malheureusement, les stashes ne peuvent pas être nommés, et seul le dernier peut être sauté (enfin, oui, c'est une pile, mais il n'y a pas vraiment de raison pour une telle limitation.) Mais alors, vous pouvez toujours intégrer les fonctionnalités manquantes dans le la source.

Il est écrit pour * ix, mais après avoir remplacé chaque "/", os.sepil fonctionne aussi bien sous Windows.

Si vous utilisez svn 1.7 ou supérieur, vous devez changer is_a_current_stash(): supprimez la ligne if ".svn" in os.listdir(CURRENT_DIR):, car il n'y a qu'un seul sous-répertoire .svn de niveau supérieur dans 1.7 WC.

cxxl
la source
Ce n'est pas pour moi sous les fenêtres! :(
Antonio Petricca
4

Vous pouvez le faire facilement en utilisant Intellij IDEA - Shelve Changes

lili
la source
Est-ce que cette façon peut gérer metadata changeset directory creates/deletes? Comme quoi exactement git stash?
wonsuc
3

une autre option consiste à copier votre paiement actuel dans un nouveau répertoire et à annuler toutes vos modifications. De cette façon, vous éviterez les tracas de la création d'une branche temporaire sur votre serveur - après tout, le stashing est une opération locale, que tout le monde ne devrait pas voir et qui peut être effectuée assez souvent.

après avoir validé votre correctif, vous pouvez mettre à jour votre copie de travail principale et supprimer votre «zone de stockage»

knittl
la source
Remarque: C'est essentiellement la même chose que d'extraire une deuxième copie de travail - uniquement sans le paiement :-).
sleske
6
@sleske: oui, sans l'énorme quantité de bande passante nécessaire pour un nouveau paiement
knittl
Qu'on le veuille ou non, c'est la réponse qui reflète de plus près le comportement de "git stash". La création d'une branche EST cool, mais est plus liée aux rayonnages TFS.
Charles Roberto Canato
1

J'ai également voulu cette fonctionnalité. J'utilise actuellement TortoiseSVN.

Je n'ai pas trouvé de solution fiable, sauf pour exporter l'arborescence, revenir au référentiel, apporter mes modifications et valider, puis comparer les modifications de l'arborescence exportée dans mon répertoire contrôlé par la source à l'aide d'un outil comme Beyond Compare.

Ou, une autre solution pourrait être de passer de la tête à un autre répertoire, d'apporter vos modifications et la validation. Une fois que vous êtes prêt à les fusionner dans votre autre copie de travail, effectuez une mise à jour et fusionnez vos modifications.

Anthony Shaw
la source
1

Je garde toujours un deuxième paiement, que j'appelle "trunk_clean". Chaque fois que j'ai besoin de faire un changement rapide et isolé lié à ce que je fais, je m'engage à la place.

angularsen
la source
0

Les idées de branchement et de correction ci-dessus sont excellentes, mais elles ne fonctionnent pas bien pour moi. J'utilise un outil de diff visuel, donc l'exécution git diffne produit pas de correctifs basés sur du texte. Notre système de construction crée un nouvel environnement chaque fois qu'une branche est créée, donc créer des branches "cachées" temporaires deviendrait compliqué.

Au lieu de cela, j'ai écrit un petit script shell qui copie un fichier dans un répertoire "étagère", ajoute un horodatage et annule la modification. Ce n'est pas aussi robuste que les solutions ci-dessus, mais cela évite également certains des pièges que j'ai rencontrés.

Ryan DeBeasi
la source
0

Sur la base de la réponse de Walter, j'ai créé les alias suivants dans mon fichier bashrc:

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'

Ces alias sont beaucoup plus faciles à utiliser et à mémoriser.

Usage:

svn.stash pour cacher les modifications et svn.stash.apply pour appliquer la cachette.

Raheel
la source
0

Dans ma pratique, j'utilise git initpour créer un référentiel Git dans le trunkrépertoire de mon référentiel Subversion, puis j'ajoute *.gitaux motifs ignorer Suctions.

Après avoir modifié certains fichiers, si je veux continuer mon travail avec la ligne principale de Subversion, je l'utilise juste git stashpour ranger mon travail. Après m'être engagé dans le référentiel Subversion, je l'utilise git stash poppour restaurer mes modifications.

yhluo
la source
2
C'est en fait une bonne solution! De nombreuses autres solutions utilisent des outils tiers pour résoudre le problème; celui-ci utilise Git comme outil tiers. Cela présente plusieurs avantages: 1) Git est très général et puissant. 2) Beaucoup de gens ont déjà installé Git.
Lii
Je suis curieux de savoir comment cela fonctionne si vous ne faites pas également de git commit.
B2K
0

Utilisation:

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

Il créera une branche à partir de l'emplacement actuel et de la révision actuelle, puis il validera les modifications de la copie de travail dans cette branche sans y basculer.

utilisation: copie SRC [@REV] ... DST

SRC et DST peuvent chacun être un chemin de copie de travail (WC) ou une URL:

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

Notez que les modifications dans la copie de travail ne seront pas automatiquement annulées (il cps'agit simplement de modifications CoPying dans une nouvelle branche) et vous devez les annuler manuellement.

Pour restaurer les modifications, vous pouvez simplement fusionner les modifications de la branche nouvellement créée avec votre copie de travail.

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

--ignore-ancestry est utilisé afin de ne pas mettre à jour les informations de fusion dans la copie de travail.

Utilisation:

svn ls -v ^/trash-stash/

pour voir ce que vous avez sur le chemin caché. Les révisions engagées sont également imprimées.

Si vous n'avez plus besoin de la cachette, lancez simplement:

svn rm ^/trash-stash/my-stash

Cette solution est meilleure que d'utiliser le correctif, car si de nouveaux changements dans la copie de travail ou sur la branche actuelle entrent en conflit avec les changements dans la cachette, vous pouvez résoudre les conflits en utilisant les moyens svn, alors que patchdans certains cas, ils échoueront ou même appliqueront le correctif de manière incorrecte.

anton_rh
la source
-1

Étant donné que Subversion ne prend pas stashparfaitement en charge la fonctionnalité,
je fais simplement une méthode manuelle comme celle-ci.

Placer Developmentet Production(release)projeter sur un chemin séparé.

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

Vous pouvez travailler toutes les nouvelles fonctionnalités de votre projet dans le chemin de développement,
et vous ne feriez que des progrès significatifs ou quelque chose devrait être publié pour l'écurie.

Lorsque vous devez le publier pour la production, ouvrez le projet de production, mettez à jour svn et faites des choses à publier (génération, exportation, etc.).

Je sais que cela rend un peu gênant, mais publier des progrès ne se produit pas souvent (ce n'est pas le cas pour moi, mais je sais que certains projets le font) comparer pour développer des progrès, de cette façon me convient.

J'utilise svn pour des projets spécifiques depuis que les membres de l'équipe de projet l'utilisent, donc je dois suivre.
La meilleure solution est d'utiliser gitun système de contrôle de version parfait et meilleur que svn.

wonsuc
la source
Ce que vous faites n'est pas très clair (quelle version est extraite dans les répertoires que vous mentionnez?), Mais cela ressemble à un doublon de la réponse la plus votée ("Extraire une nouvelle copie de travail").
sleske
@sleske Désolé, je n'ai pas lu les détails de votre cas. Dans mon cas, je n'ai besoin devque de prod2 situations. Développer des fonctionnalités complètement nouvelles serait compliqué avec svn. Je ne sais pas s'il existe une méthode claire pour résoudre votre cas dans svn world.
wonsuc