Тимчасово відкладіть незапущені зміни в Subversion (a la "git-stash")


312

Хоча програмування програмного забезпечення, яке зберігається в реверсії Subversion, я часто змінюю деякі файли, а потім помічаю, що я хотів би зробити деякі підготовчі зміни до моєї основної роботи. Наприклад, впроваджуючи нові функції, я помічаю деякий рефакторинг, який може мені допомогти.

Щоб не змішувати дві неспоріднені зміни, у цих випадках я хотів би "відсторонити" свої зміни, тобто повернутися до версії сховища, зробити деякі інші зміни, зробити ці зміни, а потім "повернути" мої зміни.

git-stash дозволяє робити саме це. Чи є якийсь спосіб зробити це за допомогою Subversion, безпосередньо або за допомогою плагіна чи сценарію. Плагіни Eclipse також будуть добре.


6
просто цікаво, але чому б не використовувати git-svn?
cmcginty

3
Деякі відповідні новини: infoworld.com/d/application-development/… (цитуючи: "Він також зазначає, що майбутній випуск Subversion 1.8 повинен наблизити його до можливостей Git, з такими функціями, як Git stash, в якому розробник може вносити зміни на місцевому рівні а потім відкладіть їх, а офлайн здійснює комісії, які записують завершені зміни, коли розробник перебуває в офлайн-режимі, і переміщується в головне сховище, коли розробник знову підключається. "
Sebastiaan van den Broek

1
Оновлення (станом на 2012-04-26): Стелаж зараз запланований на 1,9, без будь-якого еталону. Тож може зайняти деякий час ...
sleske

10
Оновлення (станом на 2012-11-17 рр.): Стелажі зараз заплановані на 1.10. Може бути, це завжди заплановано на <наступний реліз +1>? ;-)
sleske

3
Оновлення (станом на 23.03.2015, 2 роки і півтора пізніше): Хороша новина полягає в тому, що полиця ще запланована на 1.10. Погані новини: ETA: Q2 2015 (орієнтовно) Випуск 1.9.0 / 2017? (спекулятивний у кращому випадку) Випуск 1.10.0 ( subversion.apache.org/roadmap.html )
ribamar

Відповіді:


69

Коли у моїй робочій копії з'явилися незмінені зміни від одного завдання, і мені потрібно перейти до іншого завдання, я виконую одну з двох речей:

  1. Ознайомтеся з новою робочою копією другого завдання.

    або

  2. Запуск філії:

    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
    

У мене є кілька сценаріїв, які допомагають це автоматизувати.


65
це призведе до великої кількості сміття на вашому підривному сервері
knittl

3
@knittl: Ні, не буде. І що ще важливіше: це не призведе до втрачених змін, як і ваші пропозиції. Це, і маючи ще одну перевірену копію стовбура / тієї ж гілки, є єдиними двома надійними способами зробити це, що я знаю. Якщо вам це неприємно, просто перевірте іншу копію та працюйте над нею паралельно.
sbi

2
@knittl: гілка може бути створена непомітним шляхом, який знаходиться за межами розташування гілок або тегів за замовчуванням. Наприклад, команда може призначити project\temp\<creationdate-reason>або project\personal\<creationdate-reason>з цією метою.
rwong

12
Досі прикро, що гілку взагалі потрібно створити на сервері. Справа не в тому, що такі гілки копіюють багато даних, а в тому, що вони створюють безліч непотрібних посилань, без яких працює система, як git.
thepeer

8
це не корисно для великого сховища. Це абсолютно не варіант у моєму робочому середовищі. І хоча я хочу, щоб наш сховище було меншим та краще організованим, і, чесно кажучи, сховищем git замість svn, я обмежений межами того, як організований наш код у нашій організації.
AdrianVeidt

337

Ця публікація в блозі радить використовувати diff та patch.

  • git stash приблизно стає svn diff > patch_name.patch; svn revert -R .
  • git stash apply стає patch -p0 < patch_name.patch

Зауважте, що це не приховує зміни метаданих або створює / видаляє (я думаю) каталог. (Так, svn відстежує їх окремо від вмісту каталогу, на відміну від git.)


13
Це випадковий дублікат stackoverflow.com/questions/1554278 / ... - відправити upvotes там.
Вальтер Мундт

2
Це також, здається, не включає двійкові файли, що дратує. Принаймні при використанні TortoiseSVN для генерації виправлення.
angularsen

1
stackoverflow.com/questions/159853/… може допомогти у цьому.
Вальтер Мундт

6
Ви можете більш-менш відслідковувати метадані, якщо ви використовуєте svn patch patch_name.patchзамість них patch -p0, оскільки вони знаходяться у файлі патча, і svn патч розуміє їх.
мат

Це не включає зміни зовнішніх.
congusbongus

182

Ви можете зберігати свої поточні зміни svn diffу файлі патча, а потім відновити свою робочу копію:

svn diff > stash.patch
svn revert -R .

Після реалізації вашої підготовчої функції ви можете застосувати свій патч за допомогою утиліти patch:

patch < stash.patch

Як зазначають інші, це не допоможе svn:properties операціями деревом (додавання, видалення, перейменування файлів та каталогів).

Бінарні файли також можуть створювати проблеми, я не знаю, як патч (або TortoiseSVN в цьому випадку обробляє їх).


4
Можливо, це, здається, не надто добре працює з видаленими / перейменованими файлами, я думаю.
JesperE

7
Дивіться поле під назвою "Чому замість цього не використовувати патчі?" на svnbook.red-bean.com/en/1.5/…, щоб зрозуміти, чому це погана ідея.
sbi

4
@sbi: Я не вважаю, що це вагоме виправдання для протидії. Це не "погана відповідь". Це просто не ідеальна відповідь. Я не думаю, що ця людина не заслуговує покарання за його пропозицію. Ви б хотіли, щоб він не відповідав натомість? Якщо так, то так, вам слід подати заяву. Інакше це покарання за добрі наміри.
Седат Капаноглу

5
якщо будь-хто інший, як я, подумав, що це виглядає як найлегше рішення, і вирішить спробувати, мені довелося використовувати патч -p0 <stash.patch - інакше він скаржився на неможливість знайти файли для виправлення
CupawnTae

4
Ця порада особливо допомагає, якщо ви походите з git background і змушені використовувати SVN через різні причини. Невелике вдосконалення порад, вже наданих для користувачів, які вперше користуються патчем: $ patch --strip=0 < stash.patch Це дозволить переконатися, що патч не запитає у вас ім'я файлу, коли ви застосовуєте патч.
ksinkar

43

Найпростішим способом було б користуватися тимчасовою гілкою, як це:

$ 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

Це можна (і, ймовірно, повинно) містити в сценарії, якщо це робити більш регулярно.


2
Чому це знищено, тоді як "рішення" проголосуються, які навіть не працюють, коли ви видалили / додали файли або змінили будь-які властивості? Так, це не найпростіше зробити, коли ви робите це вперше, але, крім того, щоб перевірити, щоб паралельно працювала ще одна копія, це єдине рішення, яке працює у всіх випадках.
sbi

5
Добре використовувати синтаксис ^ для кореневого репо (з svn 1.6). Гарне рішення, коли ваш репо має стовбур / теги / гілки на верхньому рівні.
бендін

4
Мені не дуже подобається ставити всі ці тимчасові гілки на сервер. Я вважаю, що це потрібно робити локально, а не захаращувати сервер (і генерувати електронні листи від шпіонів, якщо ви генеруєте пошти під час реєстрації). Все-таки варіант, який варто пам’ятати.
sleske

3
@sleske: так, ви здійснюєте свою тимчасову сховище на сервері, але сама гілка видалена. У будь-якому випадку, я думаю, що це найшвидший і надійний спосіб зробити це.
JesperE

5
@sleske: SVN не є розподіленим VCS, тому все повинно бути на сервері. Це просто так.
sbi

24

Станом на 1.10.0 (2018-04-13) у вас є експериментальна svn shelveкоманда . ( TortoiseSVN підтримує команду ) Це не що інше, як помічник для збереження виправлення та повернення назад, тому він має ті ж обмеження, що і svn diff+ patch(тобто не може обробляти бінарні файли та перейменовувати). ( Редагувати : схоже, що бінарна підтримка надходить у наступній версії 1.11.0 )

Редагувати ^ 2: 1.11.0 (випускається 2018-10-30) підтримуються бінарні файли . Стелажі перейменованих файлів не підтримуються. Стелажі в 1.11 несумісні з полками, створеними 1.10.

Edit ^ 3: З 1.12.0 (випущений 2019-04-24), копіювання та перейменування які підтримуються . Стелажі в 1.12 несумісні з полицями, створеними попередніми версіями.

Edit ^ 4: Там немає ніяких змін навколо стелажів з 1.13.0 і 1.14.0 . Команди все ще позначені як експериментальні, і вам потрібно визначитись, SVN_EXPERIMENTAL_COMMANDS=shelf3щоб активувати функцію. Схоже, ця функція наразі не змінюється .

Примітки щодо дизайну можна знайти в 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

Я не знаю простий спосіб зробити це просто svn. Чесно кажучи, я б радив використовувати git-svngit repo, який виступає робочою копією svn, і просто використовувати git stashз цим. Просто замініть git pullна git svn rebaseі git pushна, git svn dcommitі ви фактично можете зберегти 90% робочого процесу в git і продовжувати спілкуватися з сервером svn.


Але посилання stackoverflow.com/questions/1554278/… Я згадую у коментарях вище, пропонує практичне рішення зробити скриньку лише у svn.
VonC

Досить справедливо; насправді google привів мене до цього рішення в блозі саме зараз. Я все ще стверджую, що для цього запитувача git-svn - це природне рішення.
Вальтер Мундт

Я сумніваюся, що рішення слід за перейменами файлів, оскільки git не робить.
NO_NAME

4

Існує невеликий скрипт Python 2, svn-stashдоступний під GPL 3: https://github.com/frankcortes/svn-stash .

Це працює як svn diff/patch згадані рішення та пропонує проштовхування та вивільнення змін, що відрізняється від деяких локальних каталогів. На жаль, не можна назвати скрині, і лише останній можна вискочити (ну, так, це стек, але немає реальної причини для такого обмеження.) Але тоді ви завжди можете вбудувати відсутні функції в джерело.

Він написаний для * ix, але після заміни кожного «/» os.sepним непогано працює і під Windows.

Якщо ви використовуєте svn 1.7 або новішої версії , вам потрібно змінити is_a_current_stash(): видалити рядок if ".svn" in os.listdir(CURRENT_DIR):, оскільки в 1.7 WC-іх є лише один підрозділ .svn верхнього рівня.


Це не для мене під вікнами! :(
Антоніо Петріка

4

Це можна легко зробити за допомогою Intellij IDEA - Shelve Changes


Чи може цей спосіб впоратися metadata changesі directory creates/deletes? Як саме те, що git stashробить?
wonsuc

3

інший варіант - скопіювати поточний замовлення в новий каталог та відновити всі зміни. таким чином ви врятуєте клопоту щодо створення тимчасової гілки на вашому сервері - адже зберігання даних - це локальна операція, яку не всі повинні бачити, і це можна зробити досить часто.

після внесення виправлень ви можете оновити свою основну робочу копію та видалити "область зберігання"


Примітка: Це по суті те саме, що перевірити другу робочу копію - тільки без оформлення замовлення :-).
sleske

6
@sleske: так, без величезної кількості пропускної здатності, необхідної для нової каси
knittl

Вам подобається чи ні, це відповідь, яка ближче відображає поведінку "git stash". Створення гілки є класним, але більше пов'язане з стелажем TFS.
Чарльз Роберто Канато

1

Я також хотів цієї функції. В даний час я використовую TortoiseSVN.

Я не знайшов жорсткого рішення, окрім експорту дерева, повернення до сховища, внесення змін і внесення змін, а потім порівняння змін із експортованого дерева назад у моєму керованому каталозі джерелом, використовуючи такий інструмент, як Beyond Compare.

Або іншим рішенням може бути відгалуження від HEAD до іншого каталогу, внесення змін та введення змін. Після того, як ви будете готові об’єднати їх назад до іншої робочої копії, проведіть оновлення та об’єднайте свої зміни.


1

Я завжди тримаю другу касу, яку я називаю "trunk_clean". Кожен раз, коли мені потрібно зробити швидку, ізольовану зміну, пов’язану з тим, що я роблю, я замість цього беру на себе зобов'язання.


0

Ідеї ​​розгалуження та виправлення вище є чудовими, але вони не добре працюють для мене. Я використовую візуальний інструмент різниці, тому запуск git diffне створює текстові виправлення. Наша система збирання створює нове середовище щоразу, коли створюється гілка, тож створення тимчасових гілок "приховування" стає безладним.

Натомість я написав невеликий скрипт оболонки, який копіює файл у каталог «полиці», додає часову позначку та повертає зміни. Це не так надійно, як рішення вище, але це також дозволяє уникнути деяких підводних каменів, в які я зіткнувся.


0

На основі відповіді Вальтера я створив такі псевдоніми у своєму файлі 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'

Ці псевдоніми набагато простіше у використанні та запам'ятовуванні.

Використання:

svn.stash для приховування змін та svn.stash.apply для застосування скриньки .


0

У своїй практиці я використовую git initдля створення сховища Git у trunkкаталозі мого сховища Subversion, а потім додаю*.git до шаблонів ігнорування Suctions.

Після зміни деяких файлів, якщо я хочу продовжувати роботу з основною лінією Subversion, я просто використовую git stashдля того, щоб приховати свою роботу. Після введення в сховище Subversion я використовую git stash popдля відновлення своїх змін.


2
Це насправді гарне рішення! Багато інших рішень використовують сторонні інструменти для вирішення проблеми; цей Git використовує як сторонній інструмент. Це має ряд переваг: 1) Git дуже загальний і потужний. 2) У багатьох людей вже встановлено Git.
Лій

Мені цікаво, як це працює, якщо ви також не зробите git.
B2K

0

Використання:

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

Він створить гілку з поточного місця розташування та поточної версії, а потім здійснить зміни в робочій копії для цієї гілки, не перемикаючись на неї.

використання: скопіюйте SRC [@REV] ... DST

SRC та DST можуть бути або робочою копією (WC) шлях або URL:

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

Зауважте, що зміни в робочій копії не будуть автоматично повернені ( cpце лише CoPying зміни в нову гілку), і вам доведеться відновити їх вручну.

Щоб відновити зміни, ви можете просто об'єднати зміни з новоствореної філії до вашої робочої копії.

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

--ignore-ancestry використовується для того, щоб не оновлювати інформацію про злиття у робочій копії.

Використання:

svn ls -v ^/trash-stash/

щоб побачити, що у вас є на скрині. Друковані зміни також надруковані.

Якщо вам більше не потрібна скринька, просто запустіть:

svn rm ^/trash-stash/my-stash

Це рішення краще, ніж використовувати патч, оскільки, якщо нові зміни в робочій копії або в поточній гілці суперечать змінам в скрині, ви можете вирішити конфлікти, використовуючи svn засоби, тоді як patchу деяких випадках просто не вдасться або навіть застосувати патч неправильно.


-1

Оскільки Subversion не підтримує stashфункцію ідеально,
я просто так роблю вручну.

Розмістіть Developmentі Production(release)проектуйте на окремий шлях.

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

Ви можете працювати з будь-якими новими можливостями для свого проекту на шляху розвитку,
і ви тільки зробите значущий прогрес, або щось має бути випущено для стайні.

Коли вам доведеться випустити його для виробництва, відкрийте виробничий проект, оновіть svn і виконайте завдання для випуску (побудова, експорт ... тощо).

Я знаю, що це робить трохи непростим, але звільнення прогресу трапляється не часто (це не для мене, але я знаю, що деякі проекти так роблять) порівнюють, щоб розвивати прогрес, цей спосіб підходить мені.

Я використовую svn для конкретних проектів, оскільки члени команди проекту використовують його, тому мені потрібно дотримуватися.
Найкращим рішенням є використання, gitяке має досконалу систему контролю версій і кращу, ніж svn.


Не зовсім зрозуміло, чим ви займаєтесь (яку версію перевіряють у згадуваних вами каталогах?), Але це схоже на дублікат відповіді вгорі («Перевірте нову робочу копію»).
sleske

@sleske Вибачте, я не прочитав ваші дані справи. У моєму випадку, я тільки потрібно devі prod, 2 ситуації. Розробити абсолютно новий функціонал було б складно з svn. Я не впевнений, чи є чіткий спосіб вирішити вашу справу у світі svn.
wonsuc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.