How can I make myself more productive with the SVN CLI? I need to complete repetitive tasks like these:

  • find modified files in directory
  • commit only SOME of them
    • selecting them somehow other then remembering their names
  • list unversioned files
    • add only some using some efective way other then remembering them
  • revert only some files in certain directory

I was used to TortoiseSVN on Windows, but a switch to OSX (which is quite linux-like) forced me to use SVN's CLI, as other clients are bad or really expensive.

  • I have a custom shell function I'll post from home that shows exactly how those operations can be done efficiently. I had the same set odd actions I was doing a lot and seemed clumsy. – Caleb Oct 31 '11 at 14:40
  • Would you guys please add what do you use for diffs? I have PHP code and the default diff is not hightlighted and makes every overview of the code changes a struggle :( – Tomáš Fejfar Nov 2 '11 at 16:00

I run into similar issues. My approach has been to write shell aliases or functions for the most common actions I take. For reference, these are ZSH shell functions. The functions themselves should work in bash too, but the shell completion stuff would be different.

In looking over your usage, the "select some" action you want to take varies from my usage and there is no provision for it. I would actually you suggest modifying your usage of revision control to make more frequent commits and take advantage of multiple working copies or branches in a repository to keep track of selective change sets. If you are working in a directory, everything you do there should either get committed or reverted on a selective basis, but not much should be left sitting around. Commit what you've got at any given moment and use revision control features to handle what goes into the product or not.

In order for this to work, you would put the code in your ~/.zshrc file (or ~/.bashrc for bash).

Here is the main function I use (every day):

function svnlist () {
    if [ -z "$2" ]; then
        case $1 in
                svn status | grep '^~' | cut -c9-
                svn status | grep '^\!' | cut -c0-
                svn status | grep '^\?' | cut -c9-
                svn status | grep '^C' | cut -c9-
        case $2 in
                $0 unknown | xargs -iX svn add "X"
                $0 missing | xargs -iX svn del "X"
            revert) $0 conflicted | xargs -iX svn revert "X"
            resolved) $0 conflicted | xargs -iX svn resolved "X"
                mkdir _tmp
                $0 clobered | while read item; do
                    mv "$item" _tmp
                    svn del "$item"
                svn ci -m "Unclobering files. (removing old)"
                mv _tmp/* .
                rmdir _tmp
                $0 unknown add
                svn ci -m "Unclobering files. (adding new)"

alias svndiff="svn diff -x -b | colordiff"
compctl -x 'p[1]' -k '(missing unknown conflicted clobered)' - 'p[2]' -k '(add del revert resolved)' -- svnlist

This should allow you to run something like svnlist unknown to find all the files in the current directory that are unversioned and svnlist unknown add to optionally add them all. svnlist clobered revert would find all the files that have been clobered after an update and revert them. svnlist conflicted resolved would mark all conflicts as resolved. svnlist missing del would mark any files missing in action as being deleted in the repository.

Also if you run into it, here is one for editing the log message of a specific revision. I don't use this so much any more but I made a lot of mistakes early on and prefer to keep the log messages tidy:

function svneditlog () {
    if ! echo $rev | pcregrep '^[0-9]+$'; then
        echo "Invalid usage. svneditlog REV"
    svn info | grep ^URL: | awk '{print $2}' | read url
    svn propedit -r $rev --revprop svn:log $url

In looking at this code, it really shows that I wrote these many years ago when I was just getting started with version control and not very graceful in a shell, but it should still work.

  • 1
    THank you very much. My usage is partly determined by the project I'm working on. I need to change some variables to make it work locally and that variables should not get to production. The project has quite a long history and I can't fix that in the old versions, that are still in use. It's been mostly fixed, but some changes are still needed. But your scripts have shown me the mind-frame i should have... thx – Tomáš Fejfar Nov 2 '11 at 15:51

Leverage your shell's completion. Bash has some completion for svn, zsh's is significantly better. For example, in zsh, svn add <TAB> completes only files that aren't already registered, svn commit <TAB> lists only files that are registered and have changes, and so on. This alone should give you most of what you're asking:

  • find modified files in directory → svn status or svn commit <TAB>
  • commit only SOME of them → svn commit <TAB>
  • list unversioned files → svn status or svn add <TAB>
  • add only some → svn add <TAB>
  • revert only some files in certain directory → svn revert <TAB>

Define aliases and functions for the commands you use most often. Here are some that I use in zsh (note that I'm transitioning towards VC-agnostic aliases; these are svn-specific shortcuts, analogous to the CVS shortcuts that I'd been using for a decade or so).

## Show file status (excluding non-controlled files)
alias svns='svn status > >(grep -v "^?")'
## Show the status of modified files (in particular, to notice potential conflicts in the next update)
svnm () {
  [[ $# -ne 0 ]] || set .
  svn merge -r BASE:HEAD --dry-run "$@" | sed -e '/^-/d'
  return $pipestatus[1]

## log (in chronological order)
svnl () {
  local since="1" cmd arg= ret=0
  if [[ $1 = <1900->-<1-12>-<1-31> ]]; then
  elif [[ $1 = <1-> ]]; then
  cmd=(svn log -r$since:HEAD)
  while [[ $1 = -* ]]; do
    cmd=($cmd $1)
  if [[ $# -ne 0 ]]; then
    for arg; do
      $cmd[@] $1
      ret=$((ret > $? ? $ret : $?))
    return $ret
## log (from the start of the present branch or the last move)
alias svnlb='svnl --stop-on-copy'

You may want to include some version control information in your prompt, with zsh's vcsinfo.

  • 1
    Thanks. Really good usage of dry run merge. I like that :) Not so sure I'll switch to zsh (switching win->unix is enough problems already), but still it's interesting use. – Tomáš Fejfar Nov 2 '11 at 15:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.