web-dev-qa-db-ja.com

Subversionのコミットされていない変更を一時的に片付ける(「git-stash」など)

Subversionリポジトリに保存されているソフトウェアをプログラミングしているときに、いくつかのファイルを変更することがよくあります。その後、メインの作業のためにいくつかの準備変更を行いたいことに気付きます。例えば。新しい機能を実装しているときに、リファクタリングが役立つことがあります。

2つの無関係な変更を混在させないために、これらの場合、変更を「格納」します。つまり、リポジトリバージョンに戻し、他のいくつかの変更を行い、これらをコミットしてから、変更を「取得」します。

git-stash はまさにそれを可能にします。 Subversionで直接、またはプラグインまたはスクリプトを使用してこれを行う方法はありますか。 Eclipseプラグインも問題ありません。

302
sleske

作業コピーの1つのタスクからコミットされていない変更があり、別のタスクに切り替える必要がある場合、次の2つのいずれかを実行します。

  1. 2番目のタスクの新しい作業コピーをチェックアウトします。

    または

  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
    

これを自動化するのに役立つスクリプトがいくつかあります。

67
bendin

このブログ投稿 diffとパッチの使用を推奨しています。

  • git stashはおよそsvn diff > patch_name.patch; svn revert -R .になります
  • git stash applypatch -p0 < patch_name.patchになります

これはメタデータの変更を隠したり、ディレクトリを作成/削除したりしないと思います。 (はい、svnはgitとは異なり、ディレクトリの内容とは別に追跡します。)

323
Walter Mundt

svn diffを使用して現在の変更をパッチファイルに保存し、作業コピーを元に戻すことができます。

svn diff > stash.patch
svn revert -R .

準備機能を実装したら、パッチユーティリティを使用してパッチを適用できます。

patch < stash.patch

他の人が指摘したように、これはsvn:propertiesおよびツリー操作(ファイルおよびディレクトリの追加、削除、名前変更)では機能しません。

バイナリファイルも問題を引き起こす可能性がありますが、パッチ(またはこの場合TortoiseSVNがそれらを処理する方法)はわかりません。

172
knittl

最も簡単な方法は、次のような一時的なブランチを使用することです。

$ 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

これは、より定期的に行われる場合、スクリプトに入れることができます(おそらくそうすべきです)。

42
JesperE

1.10.0(2018-04-13)の時点で、実験的な svn shelveコマンド があります。 ( TortoiseSVNはコマンドをサポートしています )パッチを保存して適用するのはヘルパーにすぎないため、svn diff + patchと同じ制限があります(つまり、バイナリを処理できません)ファイルと名前の変更)。 (Edit次のバージョン1.11.0でバイナリサポートが提供されるようです

Edit ^ 2:1.11.0(2018-10-30リリース)では、バイナリファイルは サポート です。シェルフの名前を変更したファイルはサポートされていません。 1.11のシェルフは、1.10で作成されたシェルフと互換性がありません。

Edit ^ 3:1.12.0(2019-04-24リリース)では、コピーと名前の変更は サポート です。 1.12のシェルフは、以前のバージョンで作成されたシェルフと互換性がありません。

デザインノートは開発者の 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
17
snipsnipsnip

Svnでそれを行う簡単な方法は知りません。正直、git-svnを使用してsvn作業コピーとして機能するgitリポジトリを作成し、git stashを使用することをお勧めします。 git pullgit svn rebaseに、git Pushgit svn dcommitに置き換えるだけで、実際にgitワークフローの90%を維持しながら、svnサーバーと通信できます。

8
Walter Mundt

GPL 3で利用可能なsvn-stashという小さなPython 2スクリプトがあります: https://github.com/frankcortes/svn-stash

前述のsvn diff/patchソリューションのように機能し、変更をローカルディレクトリへの差分としてプッシュおよびポップします。残念ながら、隠し場所に名前を付けることはできず、最後の隠し場所だけをポップすることができます(まあ、それはスタックですが、そのような制限の本当の理由はありません)。ソース。

* ix向けに書かれていますが、すべての「/」をos.sepに置き換えた後、Windowsでも同様に動作します。

Svn 1.7以降を使用する場合は、is_a_current_stash()を変更する必要があります。1.7WCには最上位の.svnサブディレクトリが1つしかないため、_if ".svn" in os.listdir(CURRENT_DIR):行を削除します。

4
cxxl

Intellij IDEAを使用して簡単に実行できます- Shelve Changes

4
lili

別のオプションは、現在のチェックアウトを新しいディレクトリにコピーし、すべての変更を元に戻すことです。これにより、すべてのスタッシングがローカル操作であるため、サーバーに一時的なブランチを作成する手間を省くことができます。

ホットフィックスをコミットした後、メインの作業コピーを更新し、「スタッシングエリア」を削除できます

3
knittl

私もこの機能が欲しかった。現在TortoiseSVNを使用しています。

ツリーをエクスポートし、リポジトリに戻して変更を加え、コミットしてから、Beyond Compareなどのツールを使用して、エクスポートされたツリーの変更をソース管理ディレクトリに戻すことを除いて、堅牢なソリューションは見つかりませんでした。

または、別の解決策は、HEADから別のディレクトリに分岐し、変更を加えてコミットすることです。それらを他の作業コピーにマージする準備ができたら、更新を行って変更をマージします。

1
Anthony Shaw

「trunk_clean」と呼ばれる2番目のチェックアウトを常に保持しています。私がやっていることに関連して、迅速かつ孤立した変更を行う必要があるときはいつでも、代わりにそのチェックアウトにコミットします。

1
angularsen

Subversionはstash機能を完全にサポートしていないため、
このように手動で操作します。

DevelopmentおよびProduction(release)プロジェクトを別々のパスに配置します。

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

開発パスでプロジェクトの新しい機能を使用できますが、
そしてあなたは意味のある進歩のみをコミットするか、安定のために何かをリリースすべきです。

本番用にリリースする必要がある場合は、本番プロジェクトを開き、svnを更新し、リリースするもの(ビルド、エクスポートなど)を行います。

私はこれが少し面倒になることを知っていますが、進行状況をリリースすることは頻繁に起こりません(私にとってはそうではありませんが、私はいくつかのプロジェクトがそうすることを知っています)。

プロジェクトチームメンバーが使用しているため、特定のプロジェクトにsvnを使用しています。したがって、従う必要があります。
最適なソリューションは、gitを使用することです。これは、完全なバージョン管理システムを備え、svnよりも優れています。

0
wonsuc

私の練習では、git initを使用して、SubversionリポジトリのtrunkディレクトリにGitリポジトリを作成し、*.gitをSuctions無視パターンに追加します。

いくつかのファイルを変更した後、Subversionメインラインで作業を続けたい場合は、git stashを使用して作業を隠します。 Subversionリポジトリにコミットした後、git stash popを使用して変更を復元します。

0
yhluo

つかいます:

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が失敗するか、パッチを誤って適用することもあります。

0
anton_rh

Walterの回答に基づいて、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
Raheel

上記のブランチとパッチのアイデアは素晴らしいですが、私にはうまくいきません。視覚的な差分ツールを使用しているので、git diffを実行してもテキストベースのパッチは作成されません。ビルドシステムは、ブランチが作成されるたびに新しい環境を起動するため、一時的な「スタッシュ」ブランチを作成すると面倒になります。

代わりに、ファイルを「棚」ディレクトリにコピーし、タイムスタンプを追加して、変更を元に戻す 小さなシェルスクリプト を作成しました。上記のソリューションほど堅牢ではありませんが、私が遭遇した落とし穴のいくつかを回避します。

0
Ryan DeBeasi