Временно отложите незафиксированные изменения в Subversion (а-ля "git-stash")
При программировании программного обеспечения, хранящегося в репозитории Subversion, я часто изменяю некоторые файлы, а затем замечаю, что хотел бы внести некоторые подготовительные изменения в свою основную работу. Например, при реализации новой функциональности я замечаю некоторый рефакторинг, который может мне помочь.
Чтобы не смешивать два несвязанных изменения, в этих случаях я хотел бы "убрать" мои изменения, то есть вернуться к версии репозитория, сделать некоторые другие изменения, зафиксировать их, а затем "извлечь" мои изменения.
git-stash позволяет делать именно это. Есть ли способ сделать это с помощью Subversion, напрямую или с помощью какого-либо плагина или скрипта. Плагины Eclipse тоже подойдут.
17 ответов
Когда я получил незафиксированные изменения от одной задачи в моей рабочей копии, и мне нужно переключиться на другую задачу, я делаю одну из двух вещей:
Проверьте новую рабочую копию для второго задания.
или же
Начать ветку:
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
У меня есть несколько сценариев, которые помогают автоматизировать это.
Этот блог советует использовать diff и patch.
git stash
примерно становитсяsvn diff > patch_name.patch; svn revert -R .
git stash apply
становитсяpatch -p0 < patch_name.patch
Обратите внимание, что это не хранит изменения метаданных или (я думаю) каталог создает / удаляет. (Да, svn отслеживает их отдельно от содержимого каталога, в отличие от git.)
Вы можете сохранить свои текущие изменения с svn diff
в файл патча, затем верните свою рабочую копию:
svn diff > stash.patch
svn revert -R .
После того, как вы реализовали свою подготовительную функцию, вы можете применить ваш патч с помощью утилиты:
patch < stash.patch
Как отметили другие, это не будет работать с svn:properties
и древовидные операции (добавление, удаление, переименование файлов и каталогов).
Бинарные файлы также могут создавать проблемы, я не знаю, как исправление (или TortoiseSVN в этом случае их обрабатывает).
Самый простой способ - использовать временную ветку, например:
$ 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
Это может (и, вероятно, должно) быть помещено в сценарий, если это делается на более регулярной основе.
По состоянию на 2018-04-13 (Subversion 1.10.0) у вас есть экспериментальный svn shelve
командование( TortoiseSVN поддерживает команду)
Начиная с 1.10.0, это не что иное, как помощник для сохранения патча и применения обратно, поэтому он имеет те же ограничения, что и svn diff
+ patch
(т.е. не может обрабатывать двоичные файлы и переименовывать). (Edit: похоже, что бинарная поддержка будет в следующей версии)
Редактировать ^2: С 1.11.0 (выпущен 2018-10-30), двоичные файлы поддерживаются. Переставленные переименованные файлы остались без поддержки. Стеллажи в 1.11 несовместимы с полками, созданными в 1.10.
Заметки о дизайне можно найти на их вики.
$ 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
Я не знаю простого способа сделать это с помощью SVN. Честно говоря, я бы посоветовал использовать git-svn
сделать git репо, который действует как рабочая копия svn, и просто используя git stash
с этим. Просто замени git pull
с git svn rebase
а также git push
с git svn dcommit
и вы можете фактически сохранить 90% своего рабочего процесса git и по-прежнему общаться с сервером SVN.
Существует небольшой скрипт на Python 2, который называется svn-stash
доступно по лицензии GPL 3: https://github.com/frankcortes/svn-stash.
Это работает как svn diff/patch
упомянутые решения и предлагает толкать и выталкивать изменения как diff в некоторый локальный каталог. К сожалению, тайники не могут быть названы, и может быть выдан только последний (ну, да, это стек, но нет реальной причины для такого ограничения.) Но тогда вы всегда можете встроить отсутствующие функции в источник.
Он написан для *ix, но после замены каждого "/" на os.sep
это хорошо работает и под Windows.
Если вы используете SVN 1,7 или выше, вам нужно изменить is_a_current_stash()
: удалить строку if ".svn" in os.listdir(CURRENT_DIR):
, поскольку в 1.7 WC есть только один subdir верхнего уровня.svn.
Вы можете сделать это легко, используя Intellij IDEA - Shelve Changes
Другой вариант - скопировать текущую кассу в новый каталог и отменить все ваши изменения. таким образом вы избавите себя от необходимости создавать временную ветвь на своем сервере - ведь копирование - это локальная операция, которую не все должны видеть и которую можно делать довольно часто.
После исправления вы можете обновить основную рабочую копию и удалить "область хранения".
Я хотел бы сделать резюме для всех упомянутых выше решений, так как в этом вопросе такая неразбериха. Некоторые ответы, получившие наибольшее количество голосов, неоднозначны, и я потратил довольно много времени на то, чтобы доказать, верна ли какая-то часть ответа или нет.
Решения:
- Получение новой рабочей копии и работа в новой копии. (Самый простой и безопасный)
- Создайте ветку -> переключитесь на новую ветку -> blablabla (некоторые говорят, что это создаст мусор на сервере SVN)
- Создать патч -> восстановить рабочую копию -> исправить обратно (отлично работает, если у вас нет недобавленных или удаленных файлов)
- Использование (см. ниже)
Я старался
2.
а также .
1.
является самым простым и безопасным. Если вы хотите сэкономить время, используйте это решение. Не элегантно, я знаю.
3.
это не мой выбор, потому что:
- вы можете создать патч с недобавленными файлами и изменениями существующих файлов. Но он не удаляет эти не добавленные файлы после создания патча. Так что делать? Мне нужно создать патч (выбрать недобавленные файлы) -> вернуть рабочую копию -> вручную удалить все эти недобавленные файлы. Это вообще не работает.
4.
будет самым элегантным способом и наиболее похожим на .
добавить недобавленные/неотслеживаемые файлы -> -> готово.
Видеть? По сравнению с
git stash -u
, с той лишь разницей, что сначала нужно добавить недобавленный файл, а затем .
Тестовая среда:
Я тестирую всех, кто использует клиент Windows Tortoise SVN с копией общего доступа к сети (SAMBA) и локальными репозиториями, созданными клиентом Windows Tortoise SVN.
Поэтому я не знаю, как все может быть иначе, если вы используете сервер SVN, который отличается от локального общего ресурса . Но я думаю
shelve
будет работать в любых ситуациях, поскольку это локальная операция/функция.
Я всегда держу вторую проверку, которую я называю "trunk_clean". Всякий раз, когда мне нужно сделать быстрое изолированное изменение, связанное с тем, что я делаю, я просто вместо этого фиксирую эту проверку.
Я также хотел эту функцию. В настоящее время я использую TortoiseSVN.
Я не нашел надежного решения, кроме как экспортировать дерево, вернуться обратно в репозиторий, внести свои изменения и зафиксировать, а затем сравнить изменения из экспортированного дерева с моим исходным каталогом, используя такой инструмент, как Beyond Compare.
Или другое решение может состоять в том, чтобы перейти от HEAD к другому каталогу, внести изменения и зафиксировать. Когда вы будете готовы объединить их с вашей другой рабочей копией, сделайте обновление и объедините ваши изменения.
Использование:
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
это просто копирование изменений в новую ветку), и вы должны отменить их вручную.
Чтобы восстановить изменения, вы можете просто объединить изменения из вновь созданной ветви в вашу рабочую копию.
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
в некоторых случаях просто не удастся или даже применить патч неправильно.
Идеи ветвления и исправления выше замечательны, но они не работают для меня. Я использую визуальный инструмент сравнения, поэтому работает git diff
не производит текстовые патчи. Наша система сборки раскручивает новую среду каждый раз, когда создается ветка, поэтому создание временных веток "stash" может стать грязным.
Вместо этого я написал небольшой сценарий оболочки, который копирует файл в каталог "полка", добавляет метку времени и отменяет изменение. Он не такой надежный, как решения, описанные выше, но он также позволяет избежать некоторых подводных камней, с которыми я столкнулся.
В своей практике я использую git init
создать Git-репозиторий в trunk
каталог моего хранилища Subversion, а затем я добавляю *.git
Присоски игнорируют закономерности.
После изменения некоторых файлов, если я хочу продолжить свою работу с основной линией Subversion, я просто использую git stash
чтобы спрятать мою работу. После фиксации в хранилище Subversion я использую git stash pop
восстановить мои модификации.
Основываясь на ответе Уолтера, я создал следующие псевдонимы в моем файле 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 для применения stash.
Так как Subversion не поддерживает stash
особенность отлично,
Я просто делаю это вручную.
Место Development
а также Production(release)
проект на отдельный путь.
source\code\MyApp -- Development
release\MyApp(release) -- Production(release)
Вы можете работать с любыми новыми функциями для вашего проекта в процессе разработки,
и вы только совершите значительный прогресс или что-то должно быть выпущено для стабильной.
Когда вам нужно выпустить его для производства, откройте производственный проект, обновите svn и выполните выпуски (сборка, экспорт... и т. Д.).
Я знаю, что это немного хлопотно, но выпуск прогресса происходит не часто (это не для меня, но я знаю, что некоторые проекты делают это) по сравнению с развитием прогресса, этот способ подходит мне.
Я использую SVN для конкретных проектов, так как члены команды проекта используют его, поэтому я должен следовать.
Лучшее решение - использовать git
которая имеет совершенную систему контроля версий и лучше, чем svn
,