= Enhanced Subversion command -- an +svn+ command wrapper [*Environment*:] Command line [Home page:] http://svn-command.rubyforge.org/ [Project site:] http://rubyforge.org/projects/svn-command [Wiki:] http://wiki.qualitysmith.com/svn-command [Author:] Tyler Rick [Copyright:] 2007 QualitySmith, Inc. [License:] {GNU General Public License}[http://www.gnu.org/copyleft/gpl.html] == Introduction This is a replacement svn command-line client meant to be used instead of the standard +svn+ command. Actually, it's a _wrapper_, not a replacement, because it still uses /usr/bin/svn to do all the dirty work. == Installation === Installation: Once per _system_ sudo gem install svn-command You will also need to run _svn_command_post_install, which will attempt to do the following: * Make the svn wrapper command *executable*: sudo chmod a+x /usr/lib/ruby/gems/1.8/gems/svn-command*/bin/* (We can't just set executables = "svn" and have it automatically install it to /usr/bin because that would cause it to wipe out the existing executable at /usr/bin/svn! If you know of a better, more automatic solution to this, please let the developers know!) (You may have to restart my terminal after doing the chmod step for bash to detect the svn command in that new location.) === Installation: Per user *Important*: You need the gem's +bin+ directory to be added to the front of your path. You may run _svn_command_post_install, which will attempt to do this for you, or you can do it manually: * Add a PATH= command to your ~/.bash_profile (or equivalent). For example: export PATH=`ls -dt --color=never /usr/lib/ruby/gems/1.8/gems/svn-command* | head -n1`/bin:$PATH" === Check to see if it's working You'll know it's working by way of two signs: * Your +svn+ command will be noticeably slower * When you type svn help, it will say: You are using svn-command, a replacement/wrapper for the standard svn command. == Features Changes to existing subcommands: * svn diff * output is in _color_* (requires +colordiff+, see below) * svn diff includes the differences from your *externals* too (consistent with how svn status includes them) so that you don't forget to commit those changes too! (pass --ignore-externals if you _don't_ want a diff of externals) * svn status * filters out distracting, useless output about externals (don't worry -- it still shows which files were _modified_) * the flags (?, M, C, etc.) are in *color*! * svn move it will let you move multiple source files to a destination directory with a single command (* You can pass --no-color to disable colors for a single command...useful if you want to pipe the output to another command or something. Eventually maybe we could make this a per-user option via .svn-command?) New subcommands: * svn each_unadded (+eu+, +unadded+) -- goes through each unadded (?) file reported by svn status and asks you what to do with them (add, delete, ignore). * svn externals -- lists all externals * svn revisions -- lists all revisions with log messages and lets you browse through them interactively * svn edit_externals (+ee+) * svn externalize * svn set_message / svn get_message / svn edit_message -- shortcuts for accessing --revprop svn:log * svn ignore -- shortcut for accessing svn:ignore property * svn view_commits -- gives you output from both svn log and from svn diff for the given changesets (useful for code reviews) * svn repository_root -- prints out the root repository URL of the working copy you are in * svn delete_svn -- causes the current directory (recursively) to no longer be a working copy (RDoc question: how do I make the identifiers like Subversion::SvnCommand#externalize into links??) = Usage / Examples == svn st _Without_ this gem installed (really long): ? gemables/subversion/ruby_subversion.rb M gemables/subversion M gemables/subversion/lib/subversion.rb A gemables/subversion/bin A gemables/subversion/bin/svn X plugins/database_log4r/tasks/shared X plugins/surveys/doc/template X plugins/surveys/tasks/shared X gemables/dev_scripts/tasks/shared X gemables/dev_scripts/lib/subversion Performing status on external item at 'plugins/database_log4r/tasks/shared' Performing status on external item at 'plugins/surveys/tasks/shared' Performing status on external item at 'gemables/subversion/doc_include/template' Performing status on external item at 'gemables/dev_scripts/tasks/shared' Performing status on external item at 'applications/underlord/vendor/plugins/rails_smith' X applications/underlord/vendor/plugins/rails_smith/tasks/shared X applications/underlord/vendor/plugins/rails_smith/lib/subversion X applications/underlord/vendor/plugins/rails_smith/doc_include/template Performing status on external item at 'applications/underlord/vendor/plugins/rails_smith/tasks/shared' M applications/underlord/vendor/plugins/rails_smith/tasks/shared/base.rake _With_ this gem installed (_much_ shorter and sweeter): ? gemables/subversion/ruby_subversion.rb M gemables/subversion M gemables/subversion/lib/subversion.rb A gemables/subversion/bin A gemables/subversion/bin/svn M applications/underlord/vendor/plugins/rails_smith/tasks/shared/base.rake == svn each_unadded My personal favorite. This command is useful for keeping your working copies clean -- getting rid of all those accumulated temp files (or *ignoring* or *adding* them if they're something that _all_ users of this repository should be aware of). It simply goes through each "unadded" file (each file reporting a status of ?) reported by svn status and asks you what you want to do with them -- *add*, *delete*, or *ignore*. > svn each_unadded What do you want to do with plugins/database_log4r/doc? (shows preview) (a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > i Ignoring... What do you want to do with applications/underlord/db/schema.rb? (shows preview) (a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > a Adding... What do you want to do with applications/underlord/vendor/plugins/exception_notification? (shows preview) (a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > d Are you pretty much *SURE* you want to 'rm -rf applications/underlord/vendor/plugins/exception_notification'? (y)es, (n)o > y Deleting... For *files*, it will show a preview of the _contents_ of that file (limited to the first 55 lines); for *directories*, it will show a _directory_ _listing_. By looking at the preview, you should hopefully be able to decide whether you want to _keep_ the file or _junk_ it. ==svn externalize / externals / edit_externals Shortcut for creating an svn:external... your_project/vendor/ > svn externalize http://code.qualitysmith.com/gemables/svn-command --as svn Between that and externals / edit_externals, that's all you ever really need! (?) > svn externals /home/tyler/code/plugins/rails_smith/tasks * shared http://code.qualitysmith.com/gemables/shared_tasks/tasks /home/tyler/code/plugins/rails_smith/doc_include * template http://code.qualitysmith.com/gemables/template/doc/template /home/tyler/code/plugins/rails_smith * svn-command http://code.qualitysmith.com/gemables/svn-command Oops, I externalled it in the wrong place! > svn edit_externals /home/tyler/code/plugins/rails_smith/tasks * shared http://code.qualitysmith.com/gemables/shared_tasks/tasks Do you want to edit svn:externals for this directory? y/N > [Enter] /home/tyler/code/plugins/rails_smith/doc_include * template http://code.qualitysmith.com/gemables/template/doc/template Do you want to edit svn:externals for this directory? y/N > [Enter] /home/tyler/code/plugins/rails_smith * svn-command http://code.qualitysmith.com/gemables/svn-command Do you want to edit svn:externals for this directory? y/N > [y] (remove that line using your favorite editor (which of course is +vim+), save, quit) You can also pass a directory name to edit_externals to edit the svn:externals property for that directory: > svn edit-externals vendor/plugins ==svn get_message / set_message / edit_message Pre-requisite for set_message/edit_message: Your repository must have a pre-revprop-change hook file. Useful if you made a mistake or forgot something in your commit message and want to edit it... For example, maybe you tried to do a multi-line commit message with -m but it didn't interpret your "\n"s as newline characters. Just run svn edit_message and fix it interactively! svn get_message -r 2325 is the same as: svn propget -r 2325 --revprop svn:log If you *just* committed it and you want to edit the message for the most-recently committed revision ("head"), there is an even quicker way to do it: You can do this: svn edit_message -r head or just this: svn edit_message == svn move You can now do commands like this: svn mv file1 file2 dir svn mv dir1/* dir (The _standard_ +svn+ command only accepts a _single_ source and a _single_ destination!) == svn revisions (revisions browser) Lets you interactively step through all revisions of a file/directory/repository. Note: You may have to svn update your working copy in order for svn log (and hence svn revisions) to be able to see the revisions you just committed. Use the --forwards flag if you want to start at the oldest revision and step forwards through time rather than starting at the latest revision and stepping backwards (the default). == svn commit === --skip-notification / --covert Added a --skip-notification / --covert option which (assuming you have your post-commit hook set up to do this), will suppress the sending out of a commit notification e-mail. This is useful if you're committing large/binary files that would normally cause the commit mailer to hang. (True, the commit mailer script should really be smart enough not to hang in the first place, but let's assume we don't have the luxury of being able to fix it...) For this option to have any effect, you will need to set up your repository similar to this: /var/www/svn/code/hooks/pre-revprop-change REPOS="$1" REV="$2" USER="$3" PROPNAME="$4" ACTION="$5" if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi if [ "$PROPNAME" = "svn:skip_commit_notification_for_next_commit" ]; then exit 0; fi echo "Changing revision properties other than those listed in $0 is prohibited" >&2 exit 1 /var/www/svn/code/hooks/post-commit #!/bin/bash REPOS="$1" REV="$2" previous_revision=`expr $REV - 1` skip_commit_notification=`svnlook propget $REPOS --revprop svn:skip_commit_notification_for_next_commit -r $previous_revision` if [[ $skip_commit_notification == 'true' ]]; then # Skipping else svnnotify \ --repos-path $REPOS \ --revision $REV \ --subject-prefix "[your repository name]" \ --revision-url 'http://code/?rev=%s' \ --to code-commit-watchers@yourdomain.com \ --handler HTML::ColorDiff \ --subject-cx \ --with-diff \ --author-url 'mailto:%s' \ --footer "Powered by SVN-Notify " \ --max-diff-length 1000 fi ==Help You can, of course, get a lits of the custom commands that have been added by using svn help. They will be listed at the end. ==Global options * --no-color (since color is on by default) * --dry-run (see what /usr/bin/svn command it _would_ have executed if you weren't just doing a dry run -- useful for debugging if nothing else) * --print-commands (prints out the /usr/bin/svn commands before executing them) * --debug (sets $debug = true) ==colordiff +colordiff+ is used to colorize svn diff commands (+ lines are blue; - lines are red) Found at: * http://www.pjhyett.com/articles/2006/06/16/colored-svn-diff * http://colordiff.sourceforge.net/ Suggestion: change the colors in /etc/colordiffrc to be more readable: plain=white newtext=green oldtext=red diffstuff=cyan cvsstuff=magenta ==Bash command completion If you want command completion for the svn subcommands (and I don't blame you if you don't -- the default command completion is much faster and already gives you completion for filenames!), just add this line to your ~/.bashrc : complete -C /usr/bin/command_completion_for_svn_command -o default svn It's really rudimentary right now and could be much improved, but at least it's a start. ==Support for code reviews, commit notification, and continuous integration systems The svn revisions command lets you browse through recent changes to a project or directory and then, for each revision that you review, you can simply press R and it will mark that revision as reviewed. svn commit accepts two custom flags, --skip-notification / --covert (don't send commit notification) and --broken (tell the continuous integration system to expect failure). =Other ==Known problems It doesn't support options that are given in this format: --diff-cmd=colordiff only this format: --diff-cmd colordiff This is a limitation of Console::Command. Fix: Show the whole thing, including this line: Fetching external item into 'glass/rails_backend/vendor/plugins/our_extensions' This doesn't work: svn propget svn:skip_commit_notification_for_next_commit --revprop -r 2498 http://code.qualitysmith.com/ --dry-run In execute(). Was about to execute this command via method :exec: "/usr/bin/svn propget --revprop -r 2498 http://code.qualitysmith.com/ svn:skip_commit_notification_for_next_commit" > svn propget svn:skip_commit_notification_for_next_commit --revprop -r 2498 http://code.qualitysmith.com/ svn: Either a URL or versioned item is required Have to do: svn propget svn:skip_commit_notification_for_next_commit http://code.qualitysmith.com/applications/profiler_test --revprop -r 2498 or > /usr/bin/svn propget svn:skip_commit_notification_for_next_commit --revprop -r 2498 http://code.qualitysmith.com/ === Slowness Is it slower than just running /usr/bin/svn directly? You betcha it is! > time svn foo real 0m0.493s > time /usr/bin/svn foo real 0m0.019s But... as with most things written in Ruby, it's all more about *productivity* than raw execution speed. _Hopefully_ the productivity gains you get from using this wrapper will more than make up for the 0.5 s extra you have to wait for the svn command. :-) If not, I guess it's not for you. ==To do Take the best ideas from these and incorporate: * /usr/lib/ruby/gems/1.8/gems/rscm-0.5.1/lib/rscm/scm/subversion.rb * /usr/lib/ruby/gems/1.8/gems/rscm-0.5.1/lib/rscm/scm/subversion_log_parser.rb * /usr/lib/ruby/gems/1.8/gems/lazysvn-0.1.3/lib/subversion.rb Possibly switch to LazySvn. After you save/edit/set an svn:externals, it should try to automatically pretty up the margins/alignment for you. Color menu_item for do you want to edit this external yes/no ==================================================================================================== Diff of externals (**don't forget to commit these too!**): ---------------------------------------------------------------------------------------------------- to use ANSI underlines/colors Done, I think: Make sure to show errors! ~/svn st * wasn't showing an error it should have been > /usr/bin/svn status change_all_externals.rb change_all_externals.sh devscripts frontend glass glass.net potluck shared svn: 'change_all_externals.rb' is not a working copy If wrapped svn ever exits with an error code (such as 1), we ought to throw a fit as well If there is an error during an update, such as this one: Fetching external item into 'glass/rails_backend/vendor/plugins/our_extensions' svn: REPORT request failed on '/!svn/vcc/default' svn: Cannot replace a directory from within it will not be displayed on screen. At least if it's an external that had the error. More at: http://wiki.qualitysmith.com/svn-command