Singkirkan sementara perubahan yang tidak terikat dalam Subversion (ala "git-stash")


312

Sementara perangkat lunak pemrograman disimpan dalam repo Subversion, saya sering memodifikasi beberapa file, kemudian perhatikan bahwa saya ingin melakukan beberapa perubahan persiapan untuk pekerjaan utama saya. Misalnya saat menerapkan fungsi baru, saya melihat beberapa refactoring yang mungkin membantu saya.

Agar tidak mencampur dua perubahan yang tidak terkait, dalam kasus ini saya ingin "menyembunyikan" perubahan saya, yaitu kembali ke versi repositori, lakukan beberapa perubahan lain, lakukan ini, lalu "ambil kembali" perubahan saya.

git-simpanan memungkinkan untuk melakukan hal itu. Apakah ada cara untuk melakukan ini dengan Subversion, baik secara langsung atau dengan beberapa plugin atau skrip. Plugin Eclipse juga akan baik-baik saja.


6
hanya ingin tahu, tetapi mengapa tidak menggunakan git-svn?
cmcginty

3
Beberapa berita yang relevan: infoworld.com/d/application-development/… (mengutip: "Ia juga mencatat bahwa rilis Subversion 1.8 yang akan datang harus mendekatkan diri dengan kemampuan Git, dengan fitur-fitur seperti Git simpanan, di mana pengembang dapat membuat perubahan secara lokal dan kemudian mengesampingkannya, dan offline berkomitmen, yang mencatat perubahan selesai ketika pengembang offline dan memindahkan ke repositori master ketika pengembang terhubung kembali. "
Sebastiaan van den Broek

1
Pembaruan (per 2012-04-26): Rak sekarang dijadwalkan untuk 1.9, tanpa ETA. Jadi mungkin perlu waktu ...
sleske

10
Pembaruan (per 2012-11-17): Rak sekarang dijadwalkan untuk 1,10. Mungkin selalu dijadwalkan untuk <rilis berikutnya +1>? ;-)
sleske

3
Pembaruan (per 2015-03-23, 2 tahun setengah): Berita baiknya adalah bahwa Shelving masih dijadwalkan untuk 1,10. Berita buruknya adalah rilis ETA: Q2 2015 (tentatif) 1.9.0 / 2017? (spekulatif terbaik) Rilis 1.10.0 ( subversion.apache.org/roadmap.html )
ribamar

Jawaban:


69

Ketika saya mendapat perubahan yang tidak dikomit dari satu tugas di copy pekerjaan saya dan saya perlu beralih ke tugas lain, saya melakukan salah satu dari dua hal:

  1. Lihat copy pekerjaan baru untuk tugas kedua.

    atau

  2. Mulai cabang:

    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
    

Saya memiliki beberapa skrip yang membantu mengotomatisasi ini.


65
ini akan menghasilkan banyak sampah di server subversi Anda
knittl

3
@ Knittl: Tidak, tidak akan. Dan yang lebih penting: Ini tidak akan menghasilkan perubahan yang hilang seperti saran Anda. Ini, dan setelah memeriksa salinan trunk / cabang yang sama, adalah satu-satunya dua cara yang dapat diandalkan untuk melakukan ini yang saya tahu. Jika Anda merasa tidak nyaman dengan ini, cukup periksa salinan lain dan kerjakan secara paralel.
sbi

2
@knittl: cabang dapat dibuat di jalur yang tidak mencolok yang berada di luar cabang atau tag lokasi proyek default. Misalnya, tim dapat menunjuk project\temp\<creationdate-reason>atau project\personal\<creationdate-reason>untuk tujuan ini.
rwong

12
Sangat disayangkan bahwa cabang harus dibuat di server sama sekali. Bukannya cabang-cabang seperti itu menduplikasi banyak data, tetapi mereka membuat banyak referensi yang tidak perlu yang tidak dimiliki oleh sistem seperti git.
teman

8
ini tidak berguna dengan repositori besar. Ini sama sekali bukan pilihan di lingkungan kerja saya. Dan sementara saya berharap repositori kami lebih kecil dan lebih terorganisir, dan sejujurnya, repositori git bukan svn, saya terbatas pada batas bagaimana kode kami diatur dalam organisasi kami.
AdrianVeidt

337

Posting blog ini disarankan menggunakan diff dan patch.

  • git stash kira-kira menjadi svn diff > patch_name.patch; svn revert -R .
  • git stash apply menjadi patch -p0 < patch_name.patch

Perhatikan bahwa ini tidak menyembunyikan perubahan metadata atau (saya pikir) direktori membuat / menghapus. (Ya, svn melacaknya secara terpisah dari konten direktori, tidak seperti git.)


13
Ini adalah duplikat disengaja dari stackoverflow.com/questions/1554278/… - kirim suara di sana.
Walter Mundt

2
Tampaknya juga tidak termasuk file biner, yang menjengkelkan. Setidaknya ketika menggunakan TortoiseSVN untuk menghasilkan tambalan.
angularsen


6
Anda dapat lebih atau kurang memiliki metadata dilacak jika Anda menggunakan svn patch patch_name.patchbukan patch -p0, karena mereka ada di file tambalan, dan svn patch memahaminya.
mat

Ini tidak termasuk perubahan ke eksternal.
congusbongus

182

Anda dapat menyimpan perubahan Anda saat ini dengan svn diffmenjadi file tambalan, lalu mengembalikan copy pekerjaan Anda:

svn diff > stash.patch
svn revert -R .

Setelah menerapkan fitur persiapan, Anda dapat menerapkan tambalan dengan utilitas tambalan:

patch < stash.patch

Seperti yang telah dicatat orang lain, ini tidak akan bekerja dengan svn:propertiesdan operasi pohon (menambah, menghapus, mengganti nama file dan direktori).

File biner juga bisa memberikan masalah, saya tidak tahu bagaimana menambal (atau TortoiseSVN dalam hal ini menangani mereka).


4
Ini mungkin tidak berfungsi dengan baik dengan menghapus / mengganti nama file, saya kira.
JesperE

7
Lihat kotak berjudul "Kenapa Tidak Menggunakan Patch?" di svnbook.red-bean.com/en/1.5/… untuk memahami mengapa ini adalah ide yang buruk.
sbi

4
@ sbi: Saya tidak berpikir itu pembenaran yang valid untuk downvote. Itu bukan "jawaban buruk". Itu bukan jawaban yang sempurna itu saja. Saya tidak berpikir orang ini pantas dihukum atas sarannya. Apakah Anda lebih suka dia tidak menjawab? Jika ya, maka ya, Anda harus downvote. Kalau tidak, ini menghukum niat baik.
Sedat Kapanoglu

5
kalau-kalau ada orang lain, seperti saya, berpikir ini terlihat seperti solusi paling ringan dan memutuskan untuk mencobanya, saya harus menggunakan patch -p0 <stash.patch - jika tidak, ia mengeluhkan tidak dapat menemukan file untuk
ditambal

4
Saran ini membantu terutama jika Anda berasal dari latar belakang git dan terpaksa menggunakan SVN karena berbagai alasan. Sebuah perbaikan kecil dalam saran yang sudah diberikan untuk pengguna tambalan pertama kali: $ patch --strip=0 < stash.patch Ini akan memastikan bahwa tambalan tidak menanyakan nama file saat Anda menerapkan tambalan Anda.
ksinkar

43

Cara termudah adalah dengan menggunakan cabang sementara, seperti ini:

$ 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

Ini bisa (dan mungkin harus) dimasukkan ke dalam naskah jika dilakukan secara lebih teratur.


2
Mengapa ini ditolak, sementara "solusi" dipilih yang bahkan tidak berfungsi ketika Anda telah menghapus / menambahkan file atau telah mengubah properti apa pun? Ya, ini bukan hal termudah untuk dilakukan ketika Anda melakukannya untuk pertama kalinya, tetapi, selain memiliki salinan lain yang diperiksa untuk bekerja secara paralel, ini adalah satu-satunya solusi yang berfungsi dalam semua kasus.
sbi

5
Penggunaan sintaks ^ ^ untuk root repo (sejak svn 1.6). Solusi bagus ketika repo Anda memiliki trunk / tag / cabang di tingkat atas.
bendin

4
Saya tidak begitu suka meletakkan semua cabang sementara ini di server. Saya merasa ini harus dilakukan secara lokal, alih-alih mengacaukan server (dan menghasilkan email checkin spurios, jika Anda menghasilkan email pada checkin). Tetap saja, opsi yang patut diingat.
sleske

3
@sleske: ya, Anda melakukan simpanan sementara ke server, tetapi cabang itu sendiri dihapus. Bagaimanapun, saya pikir ini adalah cara tercepat dan paling kuat untuk melakukannya.
JesperE

5
@sleske: SVN bukan VCS terdistribusi, jadi semuanya harus ada di server. Seperti itulah adanya.
sbi

24

Pada 1.10.0 (2018-04-13), Anda memiliki svn shelveperintah eksperimental . ( TortoiseSVN mendukung perintah ) Ini bukan apa-apa selain penolong untuk menyimpan tambalan dan menerapkan kembali, sehingga ia memiliki batasan yang sama dengan svn diff+ patch(yaitu tidak dapat menangani file biner dan mengganti nama). ( Edit : Sepertinya dukungan biner akan hadir di versi 1.11.0 berikutnya )

Sunting ^ 2: Dengan 1.11.0 (dirilis 2018-10-30), file biner didukung . Menyimpan file yang diganti nama tetap tidak didukung. Rak di 1,11 tidak kompatibel dengan rak yang dibuat oleh 1,10.

Sunting ^ 3: Dengan 1.12.0 (dirilis 2019-04-24), Menyalin dan mengganti nama didukung . Rak di 1,12 tidak kompatibel dengan rak yang dibuat oleh versi sebelumnya.

Sunting ^ 4: Tidak ada perubahan di sekitar rak dengan 1.13.0 dan 1.14.0 . Perintah masih ditandai sebagai percobaan dan Anda perlu mendefinisikan SVN_EXPERIMENTAL_COMMANDS=shelf3untuk mengaktifkan fitur. Sepertinya fitur saat ini tidak tersentuh .

Catatan desain dapat ditemukan di Wiki pengembang .

$ 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

Saya tidak tahu cara mudah untuk melakukannya hanya dengan svn. Jujur, saya sarankan menggunakan git-svngit repo yang berfungsi sebagai copy pekerjaan svn, dan hanya menggunakannya git stash. Cukup ganti git pulldengan git svn rebasedan git pushdengan git svn dcommitdan Anda benar-benar dapat menyimpan 90% dari alur kerja git Anda dan masih berbicara dengan server svn.


Tetapi tautan stackoverflow.com/questions/1554278/... Saya sebutkan di komentar di atas tidak menawarkan solusi praktis untuk melakukan simpanan hanya di svn.
VonC

Cukup adil; pada kenyataannya, google mengarahkan saya ke solusi di blog tadi. Saya masih berpendapat bahwa, untuk penanya ini, git-svn adalah solusi alami.
Walter Mundt

Saya ragu solusi mengikuti perubahan nama file, karena git tidak.
NO_NAME

4

Ada skrip Python 2 kecil yang disebut svn-stashtersedia di bawah GPL 3: https://github.com/frankcortes/svn-stash .

Ini berfungsi seperti svn diff/patch solusi yang disebutkan dan menawarkan mendorong dan muncul perubahan sebagai berbeda ke beberapa direktori lokal. Sayangnya, simpanan tidak dapat dinamai, dan hanya yang terakhir yang dapat muncul (well, yeah, itu tumpukan, tetapi tidak ada alasan nyata untuk batasan seperti itu.) Namun, Anda selalu dapat membuat fitur yang hilang ke dalam sumber.

Ini ditulis untuk * ix, tetapi setelah mengganti setiap "/" dengan os.sepitu berfungsi dengan baik di Windows juga.

Jika Anda menggunakan svn 1.7 atau lebih tinggi, Anda perlu mengubah is_a_current_stash(): menghapus baris if ".svn" in os.listdir(CURRENT_DIR):, karena hanya ada satu subdir .svn tingkat atas di 1,7 WC's.


Bukan untuk saya di bawah windows! :(
Antonio Petricca

4

Anda dapat melakukannya dengan mudah menggunakan Intellij IDEA - Shelve Changes


Apakah cara ini dapat menangani metadata changesdan directory creates/deletes? Seperti apa tepatnya git stash?
wonsuc

3

opsi lain adalah menyalin checkout Anda saat ini ke direktori baru dan mengembalikan semua perubahan Anda. dengan cara ini Anda akan menghemat kerumitan membuat cabang sementara di server Anda — setelah semua simpanan adalah operasi lokal, yang tidak semua orang harus melihat dan dapat dilakukan cukup sering.

setelah melakukan perbaikan terbaru Anda, Anda dapat memperbarui copy pekerjaan utama Anda dan menghapus "area penyimpanan" Anda


Catatan: Pada dasarnya sama dengan memeriksa copy pekerjaan kedua - hanya tanpa checkout :-).
sleske

6
@sleske: ya, tanpa sejumlah besar bandwidth yang diperlukan untuk checkout baru
knittl

Suka atau tidak, ini adalah jawaban yang lebih dekat mencerminkan perilaku "git simpanan". Membuat cabang IS keren, tetapi lebih terkait dengan rak TFS.
Charles Roberto Canato

1

Saya juga menginginkan fitur ini. Saat ini saya menggunakan TortoiseSVN.

Saya belum menemukan solusi sulit kecuali untuk mengekspor pohon, kembali ke repositori, lakukan perubahan dan komit saya, lalu bandingkan perubahan dari pohon yang diekspor kembali ke direktori yang dikontrol sumber saya menggunakan alat seperti Beyond Compare.

Atau, solusi lain mungkin untuk bercabang dari HEAD ke direktori lain, buat perubahan dan komit. Setelah Anda siap untuk menggabungkan yang kembali ke copy pekerjaan Anda yang lain, lakukan pembaruan dan gabungkan perubahan Anda.


1

Saya selalu menyimpan checkout kedua, yang saya sebut "trunk_clean". Setiap kali saya perlu melakukan perubahan yang cepat dan terisolasi terkait dengan apa yang saya lakukan, saya hanya melakukan checkout itu.


0

Ide-ide percabangan dan menambal di atas sangat bagus, tetapi itu tidak bekerja dengan baik untuk saya. Saya menggunakan alat visual diff, jadi menjalankan git difftidak menghasilkan tambalan berbasis teks. Sistem build kami memutar lingkungan baru setiap kali cabang dibuat, sehingga membuat cabang "simpanan" sementara akan berantakan.

Sebagai gantinya, saya menulis skrip shell kecil yang menyalin file ke direktori "rak", menambahkan stempel waktu, dan mengembalikan perubahan. Ini tidak sekuat solusi di atas, tetapi juga menghindari beberapa jebakan yang saya temui.


0

Berdasarkan jawaban Walter, saya telah membuat alias berikut di file bashrc saya:

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'

Alias ​​ini jauh lebih mudah digunakan dan diingat.

Pemakaian:

svn.stash untuk menyembunyikan perubahan dan svn.stash.apply untuk menerapkan simpanan.


0

Dalam praktik saya, saya menggunakan git inituntuk membuat repositori Git di trunkdirektori repositori Subversion saya, dan kemudian saya menambahkan*.git ke pola Abaikan mengabaikan.

Setelah memodifikasi beberapa file, jika saya ingin melanjutkan pekerjaan saya dengan arus utama Subversion, saya hanya menggunakan git stashuntuk menyimpan pekerjaan saya. Setelah melakukan repositori Subversion, saya gunakan git stash popuntuk mengembalikan modifikasi saya.


2
Ini sebenarnya solusi yang bagus! Banyak solusi lain menggunakan alat pihak ke-3 untuk menyelesaikan masalah; yang ini menggunakan Git sebagai alat pihak ke-3. Ini memiliki beberapa keunggulan: 1) Git sangat umum dan kuat. 2) Banyak orang sudah menginstal Git.
Lii

Saya ingin tahu bagaimana ini bekerja jika Anda juga tidak melakukan git commit.
B2K

0

Menggunakan:

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

Ini akan membuat cabang dari lokasi saat ini dan revisi saat ini, dan kemudian akan melakukan perubahan dalam copy pekerjaan ke cabang itu tanpa beralih ke sana.

penggunaan: salin SRC [@REV] ... DST

SRC dan DST masing-masing dapat berupa jalur copy pekerjaan (WC) atau URL:

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

Perhatikan bahwa perubahan dalam copy pekerjaan tidak akan secara otomatis dikembalikan ( cphanya CoPying perubahan ke cabang baru) dan Anda harus mengembalikannya secara manual.

Untuk mengembalikan perubahan, Anda bisa menggabungkan perubahan dari cabang yang baru dibuat ke copy pekerjaan Anda.

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

--ignore-ancestry digunakan agar tidak memperbarui info gabungan dalam copy pekerjaan.

Menggunakan:

svn ls -v ^/trash-stash/

untuk melihat apa yang Anda miliki di jalur simpanan. Revisi yang dilakukan juga dicetak.

Jika Anda tidak membutuhkan simpanan lagi, jalankan saja:

svn rm ^/trash-stash/my-stash

Solusi ini lebih baik daripada menggunakan tambalan di bahwa jika perubahan baru dalam copy pekerjaan atau pada konflik cabang saat ini dengan perubahan dalam simpanan, Anda dapat menyelesaikan konflik menggunakan cara svn, sedangkan patchdalam beberapa kasus hanya akan gagal atau bahkan menerapkan tambalan yang salah.


-1

Karena Subversion tidak mendukung stashfitur dengan sempurna,
saya hanya melakukan cara manual seperti ini.

Tempatkan Developmentdan Production(release)proyeksikan ke jalur yang terpisah.

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

Anda dapat mengerjakan semua fitur baru untuk proyek Anda di jalur pengembangan,
dan Anda hanya akan melakukan kemajuan yang berarti atau sesuatu harus dirilis untuk stabil.

Ketika Anda harus merilisnya untuk produksi, buka proyek produksi, perbarui svn dan lakukan hal-hal untuk dirilis (membangun, mengekspor ... dll).

Saya tahu ini membuat sedikit merepotkan, tetapi melepaskan kemajuan tidak sering terjadi (itu tidak bagi saya, tetapi saya tahu beberapa proyek melakukannya) dibandingkan dengan mengembangkan kemajuan, cara ini cocok untuk saya.

Saya menggunakan svn untuk proyek tertentu karena anggota tim proyek menggunakannya, jadi saya harus mengikuti.
Solusi terbaik adalah menggunakan gityang memiliki sistem kontrol versi sempurna dan lebih baik daripada svn.


Tidak terlalu jelas apa yang Anda lakukan (versi apa yang dicek di direktori yang Anda sebutkan?), Tetapi sepertinya duplikat dari jawaban pilihan teratas ("Lihat salinan pekerjaan baru").
sleske

@sleske Maaf, saya tidak membaca detail kasus Anda. Dalam kasus saya, saya hanya perlu devdan prod, 2 situasi. Untuk mengembangkan fungsionalitas yang sama sekali baru akan rumit dengan svn. Saya tidak yakin apakah ada metode yang jelas untuk menyelesaikan kasus Anda di dunia svn.
wonsuc
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.