Mettre temporairement les changements non engagés dans Subversion (a la " git-stash")
Lors de la programmation d'un logiciel stocké dans un repo Subversion, je modifie souvent certains fichiers, puis je remarque que j'aimerais faire des changements préparatoires pour mon travail principal. Par exemple, lors de l'implémentation de nouvelles fonctionnalités, je remarque un refactoring 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, faire d'autres modifications, les valider, puis "récupérer" mes modifications.
Git-stash permet de faire exactement cela. Y a-t-il un moyen de le faire avec Subversion, directement ou avec un plugin ou un script? Les plugins Eclipse seraient également bien.
15 réponses
Quand 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:
-
Consultez une nouvelle copie de travail pour la deuxième tâche.
Ou
-
Démarrer une branche:
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.
Cet article de blog conseille d'utiliser diff et patch.
-
git stash
devient approximativementsvn diff > patch_name.patch; svn revert -R .
-
git stash apply
devientpatch -p0 < patch_name.patch
Notez que cela ne cache pas les changements de métadonnées ou (je pense) le répertoire crée / supprime. (Oui, svn les suit séparément du contenu du répertoire, contrairement à git.)
Vous pouvez stocker vos modifications actuelles avec svn diff
dans un fichier patch, puis restaurer votre copie de travail:
svn diff > stash.patch
svn revert -R .
Après avoir implémenté votre fonctionnalité préparatoire, vous pouvez ensuite appliquer votre patch avec l'utilitaire patch:
patch < stash.patch
Comme d'autres l'ont noté, cela ne fonctionnera pas avec svn:properties
et les opérations d'arborescence (Ajouter, Supprimer, Renommer des fichiers et des répertoires).
Les fichiers binaires peuvent également donner des problèmes, Je ne sais pas comment patch (ou TortoiseSVN dans ce cas les gère).
Le moyen le 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 est fait sur une base plus régulière.
À partir du 2018-04-13 (Subversion 1.10.0), vous avez experimental svn shelve
commande . (TortoiseSVN prend en charge la commande )
Actuellement, ce n'est rien d'autre qu'une aide pour enregistrer un patch et l'appliquer, donc il a les mêmes limites que svn diff
+ patch
(c'est-à-dire ne peut pas gérer les fichiers binaires et renommer). (Edit: On dirait que le support binaire arrive à la prochaine version )
$ svn shelve --help
x-shelve (shelve): Put a local change aside, as if putting it on a shelf.
usage: 1. x-shelve [--keep-local] NAME [PATH...]
2. x-shelve --delete NAME
3. x-shelve --list
1. Save the local change in the given PATHs to a patch file, and
revert that change from the WC unless '--keep-local' is given.
If a log message is given with '-m' or '-F', include it at the
beginning of the patch file.
2. Delete the shelved change NAME.
(A backup is kept, named with a '.bak' extension.)
3. List shelved changes. Include the first line of any log message
and some details about the contents of the change, unless '-q' is
given.
The kinds of change you can shelve are those supported by 'svn diff'
and 'svn patch'. The following are currently NOT supported:
mergeinfo changes, copies, moves, mkdir, rmdir,
'binary' content, uncommittable states
To bring back a shelved change, use 'svn x-unshelve NAME'.
Shelved changes are stored in <WC>/.svn/shelves/
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:
--delete : delete the shelved patch
--list : list shelved patches
-q [--quiet] : print nothing, or only summary information
--dry-run : try operation but make no changes
--keep-local : keep path in working copy
(...)
$ svn unshelve --help
x-unshelve (unshelve): Bring a shelved change back to a local change in the WC.
usage: 1. x-unshelve [--keep-shelved] [NAME]
2. x-unshelve --list
1. Apply the shelved change NAME to the working copy.
Delete the patch unless the '--keep-shelved' option is given.
(A backup is kept, named with a '.bak' extension.)
NAME defaults to the most recent shelved change.
2. List shelved changes. Include the first line of any log message
and some details about the contents of the change, unless '-q' is
given.
Any conflict between the change being unshelved and a change
already in the WC is handled the same way as by 'svn patch',
creating a 'reject' file.
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:
--keep-shelved : do not delete the shelved patch
--list : list shelved patches
-q [--quiet] : print nothing, or only summary information
--dry-run : try operation but make no changes
(...)
Je ne connais pas de moyen facile de le faire avec juste svn. Honnêtement, je conseillerais d'utiliser git-svn
pour faire un repo git qui agit comme une copie de travail svn, et juste en utilisant git stash
avec cela. Remplacez simplement git pull
par git svn rebase
et git push
par git svn dcommit
et vous pouvez réellement conserver 90% de votre flux de travail git et toujours parler à un serveur svn.
Il existe un petit script Python 2 appelé svn-stash
Disponible sous GPL 3: https://github.com/frankcortes/svn-stash .
Cela fonctionne comme les solutions svn diff/patch
mentionnées et offre la poussée et l'éclatement des changements en tant que diffs dans un répertoire local. Malheureusement, les cachettes ne peuvent pas être nommées, et seul le dernier peut être sauté (Eh bien, oui, c'est une pile, mais il n'y a pas de vraie raison pour une telle limitation.) Mais alors, vous pouvez toujours construire les fonctionnalités manquantes dans le source.
Il est écrit pour * ix, mais après avoir remplacé chaque " / " par os.sep
cela fonctionne aussi bien sous Windows.
Si vous utilisez svn 1.7 ou supérieur, vous devez changer is_a_current_stash()
: supprimer la ligne if ".svn" in os.listdir(CURRENT_DIR):
, car il n'y a qu'un seul niveau supérieur .svn subdir dans 1.7 WC.
Vous pouvez le faire facilement en utilisant Intellij IDEA - Shelve Changes
Une autre option consiste à copier votre commande actuelle dans un nouveau répertoire et à annuler toutes vos modifications. de cette façon, vous économiserez 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 peut être fait assez souvent.
Après avoir validé votre correctif, vous pouvez mettre à jour votre copie de travail principale et supprimer votre "zone de stockage"
J'ai aussi voulu cette fonctionnalité. J'utilise actuellement TortoiseSVN.
Je n'ai pas trouvé de solution hardfast sauf pour exporter l'arborescence, revenir au référentiel faire mes modifications et valider, puis comparer les modifications de l'arborescence exportée dans mon répertoire contrôlé par la source en utilisant un outil comme Beyond Compare.
Ou, une autre solution pourrait être de brancher de la tête à un autre répertoire, faire vos modifications et le commit. Une fois que vous êtes prêt à fusionner ceux de retour à votre autre copie de travail, faites une mise à jour et fusionnez vos modifications.
Je garde toujours une deuxième caisse, 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 juste sur cette caisse à la place.
Les idées de branchement et de correction ci-dessus sont géniales, mais elles ne fonctionnent pas bien pour moi. J'utilise un outil de diff visuel, donc l'exécution de git diff
ne 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, de sorte que la création de branches temporaires "stash" deviendrait désordonnée.
Au lieu de cela, j'ai écrit un petit script shell {[5] } qui copie un fichier dans un répertoire "étagère", ajoute un horodatage et rétablit la modification. Ce n'est pas aussi robuste que les solutions ci-dessus, mais il évite également certains des pièges que j'ai rencontrés.
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.
Utilisation:
svn.stash {[9] } pour stocker les modifications et svn.Stash.appliquer appliquer cachette.
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 à cette branche sans y passer.
Utilisation: copiez 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 de la copie de travail ne seront pas automatiquement annulées ({[5] } est juste copiant les modifications apportées à une nouvelle branche) et vous devez annuler - les manuellement.
Pour restaurer les modifications, vous pouvez simplement fusionner les modifications de la branche nouvellement créée vers 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 à ranger chemin. Les révisions engagées sont également imprimées.
Si vous n'avez plus besoin de la cachette, exécutez simplement:
svn rm ^/trash-stash/my-stash
Cette solution est meilleure que d'utiliser patch en ce que si de nouveaux changements dans la copie de travail ou sur le courant conflit de branche avec les changements dans la Réserve, vous pouvez résoudre les conflits en utilisant des moyens svn, alors que patch
dans certains cas échouera ou même appliquera le patch de manière incorrecte.
Dans ma pratique, j'utilise git init
pour créer un référentiel Git dans le répertoire trunk
de mon référentiel Subversion, puis j'ajoute *.git
aux Suctions ignore patterns.
Après avoir modifié certains fichiers, si je veux continuer mon travail avec la ligne principale Subversion, j'utilise simplement git stash
pour stocker mon travail. Après m'être engagé dans le dépôt Subversion, j'utilise git stash pop
pour restaurer mes modifications.