I've written about the differences between SVN and CVS and the usage of the plugins in Eclipse, see also 2006-02-01.
I found the svn import syntax a bit funny, but that might just be me. If you're importing from the commandline, do it like this:
$ cd myproject $ svn import http://machinename/subversion/myproject
I'm assuming here that you use the http protocol to access the subversion protocol; most do it that way. However it's also possible to create a file-based repository. If the admin likes that better, then import as follows. (I'm assuming here the admin has given you the path /var/www/svn/repos but that might be different!)
$ cd myproject $ svn import file:///var/www/svn/repos/myproject
Your source is NOT versioned yet. So, continue with something like:
$ cd .. $ mv myproject myproject.backup $ svn checkout http://machinename/subversion/myproject or $ svn checkout file:///var/www/svn/repos/myproject
Check the result:
$ cd myproject $ svnversion .
SVN should answer "I'm sorry Dave, I'm afraid I can't do that", or if it's in a better mood, "Revision 1".
Private projects can grow bigger than expected. Such a project may be sitting in a private repository and to keep access rights simple, it's useful to move a growing project to its own repository. I assume a new repository has been created.
First export the directory from the old repository:
$ svn export http://localhost/svn/my_private_repository/libs/lib_tool
What results is a directory called 'lib_tool', stripped of all evidence that it once resided in SVN.
Now import that same directory into the new repository called 'lib_tool'.
$ cd lib_tool $ svn import http://localhost/svn/lib_tool
If the import was successful, delete the directory you just imported, and check out the fresh first version:
$ cd .. $ rm -rf lib_tool $ svn checkout http://localhost/svn/lib_tool Checked out revision 1.
It's probably best to do an 'svn delete' in the old repository:
$ svn delete -m "Moved to its own repository" \ http://localhost/svn/my_private_repository/libs/lib_tool
There's a couple things that are easily done via Subversion's properties.
Store the executable bit of shell scripts or Python scripts or what have you:
$ svn propset svn:executable ON somescript
Some files are generated and you don't want these in your status lists:
$ svn stat ? test/leon3 ? eqm/leon3
SVN does ignore files its own way, through a property. To ignore certain files, do:
$ cd test $ svn propedit svn:ignore .
(An editor pops up, type in the filenames you want to have ignored, separated by enter)
$ cd ../eqm $ svn propedit svn:ignore . $ cd .. $ svn commit -m "Added Eclipse project files to ignorelist" .
Note that propedit has a -R switch to make the property recursively in all subdirectories.
SVN also uses properties for keyword substitution. Enter any of $Date$, $Revision$, $Author$, $HeadURL$ or $Id$ in your file and then do:
$ svn propset svn:keywords "Revision" filename $ svn commit -m "Added property for keywords" filename
When you want to specify, or add, additional keywords, separate them with a space:
$ svn propset svn:keywords "Date Author" filename
To remove:
$ svn propdel svn:keywords filename property 'svn:keywords' deleted from 'filename'.
If you want to move from CVS to SVN, there are all sorts of fancy tools. What I did for small projects was the following:
$ for i in `find . -type d -name CVS`; do svn delete $i; done $ svn commit -m "Deleted superfluous CVS directories"
If you deleted a file with "svn rm", but haven't committed yet, then just use the "revert" command.
$ svn stat D instrumentstateview.py D instrumentstate.py A + parameterpresetsview.py $ svn revert instrumentstate.py Reverted 'instrumentstate.py'
Voila...
To undelete (or as the documentation says, "resurrect") a file or directory, use the copy command, together with the exact revision.
In the example below, I had to get back the directory "shamroc" from the trunk. First, I needed to find it:
$ svn log -v http://subversion.example.org/svn/ed_software/trunk | less
Searching for the directory name, I found I deleted it in revision 3128. So I need the copy of that directory in revision 3127. First, I check out the current copy of trunk:
$ svn co http://subversion.example.org/svn/ed_software/trunk
Then I change into the directory, and copy the deleted directory into the current directory. Then it's possible to commit the change:
$ svn copy ^/trunk/shamroc@3127 ./shamroc ..... ..... A shamroc/scripts/adc_styx/linearitybuf.pl A shamroc/scripts/adc_styx/noise1.pl A shamroc/scripts/adc_styx/steps.pl A shamroc/scripts/adc_styx/dacadctest.pl A shamroc/scripts/adc_styx/boardpower.pl Checked out revision 3127. A shamroc $ svn ci -m "Resurrected the shamroc directory" Adding shamroc Committed revision 3783. $
Suppose you inadvertently made changes in some files some time back. You can examine revisions of files with
$ svn log ccsds.h
You think that the correct revision was 205. So you diff it:
$ svn diff -r 205 ccsds.h
You then decide that yes, you want to roll back the file to that revision to the current revision 270 and then commit it. You can specify the current revision as a number (270 in my case), or just type HEAD (yes, all capitals), which SVN will understand:
$ svn merge -r HEAD:205 ccsds.h U ccsds.h $ svn commit -m "Rolled back inadvertent changes" Transmitting file data .... Sending ccsds.h Committed revision 271.
Done!
Note: if you just want the previous version back, you can use the keyword PREV instead of the specific revision; i.e.
$ svn merge -rHEAD:PREV ccsds.h --- Reverse-merging r271 through r205 into 'ccsds.h': U ccsds.h
For some reason, I've had situations where it doesn't work, and instead SVN would say "so-and-so.h is not under version control"; I'd then revert the whole directory if the action was just deleting of files, but first do a dry run:
$ svn merge --dry-run -rHEAD:PREV .
And then if the output looks good, leave out the --dry-run option.
Darn, you accidentally committed some changes! Your last command looks as follows:
$ svn ci -m "Checking in one file" Sending gui/src/file1.cpp Sending python/mylib/file2.py Sending python/test_scripts/file3.py Sending python/test_scripts/file4.py Transmitting file data ....... Committed revision 3250
You only wanted to commit file1.cpp. To revert the others, issue the following command for each file:
$ svn merge -r HEAD:PREV python/mylib/file2.py $ svn merge -r HEAD:PREV python/test_scripts/file3.py $ svn merge -r HEAD:PREV python/test_scripts/file4.py $ svn ci -m "Reverting inadvertently commited files" Sending python/mylib/file2.py Sending python/test_scripts/file3.py Sending python/test_scripts/file4.py Transmitting file data ....... Committed revision 3251
If you want to continue working on the files you had, just merge them again from PREV to HEAD:
$ svn merge -rHEAD:PREV python/mylib/file2.py $ svn merge -rHEAD:PREV python/test_scripts/file3.py $ svn merge -rHEAD:PREV python/test_scripts/file4.py
...and continue hacking away without bothering anyone. The situation is now as it was before. Note that a simple "svn stat" will display the status "Modified" correctly, like when you did before the first (erroneous) commit.
If you are in a source tree and you want to know what revision is there, just type:
$ svnversion .
To incorporate this into your source files, check out this FAQ.
Sometimes, you do a release of a particular directory in your repository, and you want to re-create that release later. For instance, you have the repository my_department, in which you have the subdirectory trunk/embedded_software/superwidget.
You don't want to branch the whole trunk but rather, you want to mark that subdirectory so you can always refer to it later. This is called tagging. Technically, it's the same as branching in SVN, but we use it somewhat differently.
Move into your repository directory. A possible layout could be:
$ cd my_department $ ls trunk/ branch-version-1.0 branch-version-1.1
Then create a tags subdirectory:
$ mkdir tags
Then tag a subdirectory deep in your trunk:
$ svn copy trunk/embedded_software/superwidget \ tags/superwidget-release-client-CompanyInc A tags/superwidget-release-client-CompanyInc $ svn ci -m "Added tag for specific release for client Company Inc." Adding tags/superwidget-release-client-CompanyInc Committed version 12355. $
You don't actually need to be in the repository directory for the copy action; it can work with URLs as well. For more info, check the SVN manual on svn copy.
Sometimes, you start working on a revision to find out later that your work is huge and others have been committing all the time. In hindsight, creating a new branch would've been a good idea. To correct this, first you'll want to create a patch of all your changes:
$ cd your/current/project/directory $ svn diff > ~/hackwork.patch
Then find out what revision you are hacking:
$ svnversion . 590M
Now create a separate branch of the original version:
$ svn copy http://subversion.company.com/svn/telis/tuce \ http://subversion.company.com/svn/telis/tuce-branch-gron \ -m "Creating separate branch for work outside integration efforts" Committed revision 606.
Go to another directory, in my case ~/workspace
$ cd ~/workspace $ svn co http://subversion/svn/telis/tuce-branch-gron $ cd tuce-branch-gron
And now integrate your changes again, and commit them in the branch:
$ patch -p 0 < ~/gron.patch patching file tdb/mysql-telis.sql patching file client/python/plotffo.py ... lines removed ... $ svn commit -m "Fixes made on colors in FFO plot, conversion housekeeping \ macro different, conversion FFO plot corrected"
This happens when you're done hacking away on your branch, and now you want to test your changes together with the latest work on trunk.
First, in your branch its working directory, find out the revision that you started your branch:
$ svn log --verbose --stop-on-copy | tail -20 [ removed some stuff here ] ------------------------------------------------------------------------ r4559 | yourusername | 2014-01-10 10:34:24 +0100 (Fri, 10 Jan 2014) | 2 lines Changed paths: A /branches/branch_lorem (from /trunk:4558)Branch for working on lorem ipsum.
------------------------------------------------------------------------
OK, it's revision 4559 that we branched. Then, see what would happen if you merged your trunk back into your branch:
$ svn merge --dry-run -r4559:HEAD https://your_repository/svn/trunk/
A list of changed/deleted files and directories will follow. If you're satisfied, repeat the above command without the --dry-run option, compile and do your tests.
Go to your branch directory and find out the last revision:
$ svn log --verbose --stop-on-copy | tail -20 ... ... r608 | bartvk | 2007-02-02 12:20:55 -0100 (Fri, 02 Feb 2007) | 1 line .. ..
It should also show the comment that you entered when you created a branch then committed.
Go to the trunk directory and make sure everything's committed. Then find out the current revision with
$ svnversion . 668
Then see what would happen with a dry-run merge:
$ svn merge --dry-run -r 608:668 http://subversion/svn/mybranch/
You'll see a whole list of modifications, additions, deletions and probably lots of conflicts (beginning the line with a capital C).
Now merge the whole branch into the trunk:
$ svn merge -r 608:668 http://subversion/svn/mybranch/
Check what files are conflicted:
$ svn status | grep "^C"
For each file:
When all conflicts have been merged, you can compile and test your code. If everything's well, you can do a commit, remove the old branch and commit again:
$ svn commit -m "Merged branch xxx into trunk with changes x, y and z" $ svn delete mybranch $ svn commit -m "Removed branch xxx"
Sometimes you need to revisit a particular change. So you type 'svn log' to see which revision you made the change. You spot that you made the change in revision 45. To see what files changed from revision 44 to 45, do:
$ svn diff -r44:45 --summarize M themes/Outlet/style/style.css M includes/meta.php M modules/Outlet/language/lang-dutch.php M modules/Outlet/index.php M modules/Outlet/functions.php A issues/keywords_issue.sql
To create a new project, there are two options:
I'm assuming your SVN directory is /var/www/svn. This directory should have owner apache, group dev (or some other common development group), and rights set to rwxrwsr-x (octal 4775).
Anyone in the development group can then create a project with:
$ svnadmin create /var/www/svn/newprojectname
Depending on the umask of the creating user, the directory will probably have to be made writeable for the group:
$ chmod g+w /var/www/svn/newprojectname
After this, other developers can check out and update the new project:
$ svn co file:///var/www/svn/newprojectname Checked out revision 0.
Check out which file is used to specify username/password, and the list of projects (with their associated usernames). This can be found in the Apache configuration file. For Debian, this is /etc/apache2/mods-enabled/dav_svn.conf. The option AuthUserFile specifies the username/password file. The option AuthzSVNAccessFile specifies who has access to which project.
Then the Subversion repository can be created with:
$ svnadmin create /var/www/svn/newprojectname
And Apache needs read/write access. For Debian, this is done with a quick:
$ chmod -R www-data:www-data /var/www/svn/newprojectname
Subversion has a couple of authentication backends, personally I use accounts separate from the normal UNIX accounts. Thus, the authentication is handled via the webserver Apache. This involves a htpasswd file somewhere outside of the SVN directory, such as /var/www/private. The file can be edited with the htpasswd utility. Apache has to be configured as such, on CentOS this would mean creating a file below /etc/httpd/conf.d with the following contents:
<Location /svn> DAV svn SVNParentPath /var/www/svn
#SSLRequireSSL
AuthType Basic AuthName "My Very Special Subversion" AuthUserFile /var/www/private/htpasswd Require valid-user </Location>
When you're asked to do a code review on a branch, basically you'll want to check out the branch, then see all changes since the branch:
After checking out the branch, find the first revision since branching:
$ svn log --verbose --stop-on-copy | tail
For an overview file-wise:
$ svn diff --summarize -r3391:HEAD | less
Then, review each file with:
$ svn diff -r3391:HEAD path/to/the/filename.c
Or, as one big diff:
$ svn diff -r3391:HEAD | less
If the Subversion repository is moved from one server to another, you can easily switch to the new one without doing a complete download, or a checkin/checkout first. Type "svn info" in your project directory to find the old URL. The new URL should be supplied by your friendly neighborhood sysadmin. Then type:
$ svn switch --relocate http://oldmachine/svn/projectname/trunk \ http://newmachine/svn/projectname/trunk
The same command can be used to switch the way you connect to the server. To start using SSH, do something like:
$ svn switch --relocate http://domainname/svn/projectname/trunk \ svn+ssh://domainname/var/www/svn/projectname/trunk
Of course, this assumes you have an SSH account on the box.