Временно удалите незавершенные изменения в Subversion (a la "git -stash" ).

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

Чтобы не смешивать две несвязанные изменения, в этих случаях я хотел бы "убрать" мои изменения, то есть вернуться к версии репозитория, внести некоторые другие изменения, зафиксировать их, а затем "вернуть" мои изменения.

git-stash позволяет делать именно это. Есть ли способ сделать это с помощью Subversion, либо напрямую, либо с помощью какого-либо плагина или script. Плагины Eclipse также будут прекрасными.

Ответ 1

Когда я получил незафиксированные изменения от одной задачи в моей рабочей копии, и мне нужно переключиться на другую задачу, я делаю одну из двух вещей:

  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
    

У меня есть несколько сценариев, которые помогают автоматизировать это.

Ответ 2

Это сообщение в блоге советует использовать diff и patch.

  • git stash примерно становится svn diff > patch_name.patch; svn revert -R .
  • git stash apply становится patch -p0 < patch_name.patch

Обратите внимание, что это не сбрасывает изменения метаданных или (я думаю) каталог создает/удаляет. (Да, svn отслеживает их отдельно от содержимого каталога, в отличие от git.)

Ответ 3

Вы можете сохранить текущие изменения с помощью svn diff в файл патча, а затем вернуть свою рабочую копию:

svn diff > stash.patch
svn revert -R .

После того, как вы внедрили свою подготовительную функцию, вы можете применить исправление с помощью утилиты patch:

patch < stash.patch

Как отмечали другие, это не будет работать с svn:properties и деревом (добавить, удалить, переименовать файлы и каталоги).

Двоичные файлы также могут создавать проблемы, я не знаю, как патч (или TortoiseSVN в этом случае обрабатывает их).

Ответ 4

Самый простой способ - использовать временную ветку, например:

$ 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

Это может (и, вероятно, должно) быть помещено в script, если сделать это более регулярно.

Ответ 5

Начиная с 1.10.0 (2018-04-13) у вас есть экспериментальная команда svn shelve. (TortoiseSVN поддерживает команду) Это всего лишь помощник для сохранения патча и применения обратно, поэтому он имеет те же ограничения, что и svn diff + patch (т.е. не может обрабатывать двоичные файлы и переименовывать). (Edit: похоже, что бинарная поддержка будет в следующей версии 1.11.0)

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

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

Замечания по дизайну можно найти на вики разработчиков.

$ 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 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

Ответ 6

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

Ответ 7

В GPL 3 есть небольшой Python 2 script, называемый svn-stash: https://github.com/frankcortes/svn-stash.

Он работает как упомянутые решения svn diff/patch и предлагает pushing и popping изменений, как отличается от некоторого локального каталога. К сожалению, штампы не могут быть названы, и может быть выведен только последний (ну, да, это стек, но нет никаких оснований для такого ограничения). Но тогда вы всегда можете создавать недостающие функции в источник.

Он написан для * ix, но после замены каждого "/" на os.sep он отлично работает и под Windows.

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

Ответ 9

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

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

Ответ 10

Мне тоже нужна эта функция. В настоящее время я использую TortoiseSVN.

Я не нашел решение hardfast, кроме как экспортировать дерево, вернусь обратно в репозиторий, сделаю свои изменения и фиксацию, а затем сравните изменения с экспортированным деревом в моем исходном каталоге с помощью инструмента, такого как Beyond Compare.

Или другим решением может быть отделение от HEAD до другого каталога, внесение изменений и фиксация. После того, как вы захотите объединить их с другой рабочей копией, выполните обновление и слейте свои изменения.

Ответ 11

Я всегда держу вторую проверку, которую я называю "trunk_clean". Всякий раз, когда мне нужно сделать быстрое, изолированное изменение, связанное с тем, что я делаю, я просто беру на себя эту проверку.

Ответ 12

Идеи разветвления и исправления выше - это здорово, но они не работают хорошо для меня. Я использую инструмент визуального разграничения, поэтому запуск git diff не создает текстовые исправления. Наша система сборки создает новую среду каждый раз, когда создается ветвь, поэтому создание временных ветвей "stash" становится беспорядочным.

Вместо этого я написал небольшую оболочку script, которая копирует файл в "полку", добавляет временную метку и возвращает изменение. Это не так надежно, как решения выше, но также позволяет избежать некоторых ошибок, с которыми я столкнулся.

Ответ 13

В своей практике я использую git init для создания Git-репозитория в trunk каталоге моего Subversion-репозитория, а затем добавляю *.git к шаблонам игнорирования Suctions.

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

Ответ 14

Основываясь на ответе Уолтера, я создал следующие псевдонимы в моем файле 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.

Ответ 15

Использование:

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 в некоторых случаях просто не удастся или даже применяет исправление неправильно,

Ответ 16

Так как Subversion не поддерживает функцию stash,
Я просто делаю ручной способ, как это.

Поместите проект Development и Production(release) в отдельный путь.

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

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

Когда вам нужно выпустить его для производства, откройте производственный проект, обновите svn и выполните выпуски (сборка, экспорт... и т.д.).

Я знаю, что это немного хлопотно, но выпуск прогресса происходит не часто (это не для меня, но я знаю, что некоторые проекты делают это) по сравнению с развитием прогресса, этот способ подходит мне.

Я использую SVN для конкретных проектов, так как члены команды проекта используют его, поэтому я должен следовать.
Лучшее решение - использовать git который имеет совершенную систему контроля версий и лучше, чем svn.