# pysvn Programmer's Guide

This guide gives an tutorial introduction to the pysvn module.

Complete and detailed infomation on the pysvn API is documented in pysvn Programmer's Reference.

The pysvn module is a python interface to the Subversion version control system. This API exposes client interfaces for managing a working copy, querying a repository, and synchronizing the two.

This API cannot create new repositories; it can only interact with existing repositories. If you need to create a repository, use the svnadmin command from Subversion.

Using the API, you can check out a working copy, add, edit, and remove working files, and check in, compare, or discard your changes. Repository properties such as keyword expansion, end of line characters, and ignore lists can also be examined and manipulated.

## Subversion model

Subversion operates on an update-edit-commit model. A local, working copy is created. Changes are made in the working copy, then committed to the central repository (which may be local or remote).

This model allows and in fact expects that multiple people will occasionally edit the same file at the same time. In most cases, Subversion merges these differences without intervention. In the rare case where the differences are ambiguous, one of the commits fails, and the user or application will need to examine and resolve the differences before attempting to commit again.

## Common Tasks

This section gives examples of common tasks using the pysvn interface. Operations applied to directories are processed recursively. Add the argument `recurse=False` to prevent this behavior; for example, you may want to add a directory without adding its contents.

### Check out a working copy

    import pysvn
    client = pysvn.Client()
    #check out the current version of the pysvn project
    client.checkout('http://localhost/example/trunk',
        './examples/pysvn')
    #check out revision 11 of the pysvn project
    client.checkout('http://localhost/example/trunk',
       './examples/pysvn-11',
       revision=pysvn.Revision(pysvn.opt_revision_kind.number, 11))

This example creates a working copy of the example project in the directory examples/pysvn. This project is used in the remaining examples.

### Add a file or directory to the repository

    import pysvn
    # write a file foo.txt
    f = file('./examples/pysvn/foo.txt', 'w')
    f.write('Sample versioned file via pithon\n')
    f.close()
    client = pysvn.Client()
    #schedule the addition;
    #  the working copy will now track the file as a scheduled change
    client.add('./examples/pysvn/foo.txt')
    #committing the change actually adds the file to the repository
    client.checkin(['./examples/pysvn/foo.txt'], 'Adding a sample file')

This example creates the file `'foo.txt'` in the working copy, then adds it to the repository. Note that the `Client.import_()` command does the addition and commit in a single step. Most applications, however, queue up multiple changes and commit them together at a later time.

### Update the working copy

    import pysvn
    client = pysvn.Client()
    client.update('./examples/pysvn')

Updating gets any changes other users have committed to the repository and applies them to your working copy. Most applications do this on a regular basis to prevent conflicts.

### Commit changes to the repository

    import pysvn
    # edit the file foo.txt
    f = open('./examples/pysvn/foo.txt', 'w')
    f.write('Sample versioned file via python\n')
    f.close()
    # checkin the change with a log message
    client = pysvn.Client()
    client.checkin(['./examples/pysvn'], 'Corrected spelling of python in foo.txt')

Commits in Subversion are atomic. Either all scheduled changes are successfully committed, or none are. Most applications either commit all changes in the working copy, as shown in this example, or pass a list of individual files and directories that need to be committed as a unit.

### Discard changes in the working copy

    import pysvn
    # edit the file foo.txt
    f = file('./examples/pysvn/foo.txt', 'w')
    f.write('This change will never be seen\n')
    f.close()
    #discard the edits
    client = pysvn.Client()
    client.revert('./examples/pysvn/foo.txt')

This discards any uncommitted changes in the working copy and restores a file or directory to its unedited state.

Files that are scheduled for addition or removal remain unversioned or are restored to the working copy, respectively.

### Rename or move a file

    import pysvn
    client = pysvn.Client()
    #rename the file client side
    client.move('./examples/pysvn/foo.txt', './examples/pysvn/foo2.txt')
    #checkin the change removes the file from the repository
    client.checkin(['./examples/pysvn/foo.txt', './examples/pysvn/foo2.txt'], 'Foo has become Foo2')

Moving or renaming a file removes the file under the old path or name and adds it in the new location while preserving information about previous versions.

In this example, we passed both filenames to `Client.checkin()`. Passing the parent directory would also have been effective.

The move and checkin can be done in a single step on the server side; see the example in the Respository Tasks section.

### Remove a file or directory from the repository

    import pysvn
    client = pysvn.Client()
    #schedule the removal;
    #  the file will be removed from the working copy
    client.remove('./examples/pysvn/foo2.txt')
    #committing the change removes the file from the repository
    client.checkin(['./examples/pysvn/foo2.txt'], 'Removing sample file')

Some people confuse removing a file or directory from the repository with purging it completely. The file still exists in previous versions and can be retrieved by checking out or otherwise examining the contents of a previous revision.

Files are typically removed from the working copy immediately, while directories usually remain in the working copy until the removal is committed.

### Determine pending changes

    import pysvn
    client = pysvn.Client()
    changes = client.status('./examples/pysvn')
    print 'files to be added:'
    print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.added]
    print 'files to be removed:'
    print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.deleted]
    print 'files that have changed:'
    print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.modified]
    print 'files with merge conflicts:'
    print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.conflicted]
    print 'unversioned files:'
    print [f.path for f in changes if f.text_status == pysvn.wc_status_kind.unversioned]

## Generating a diff or patch

    import pysvn
    client = pysvn.Client()
    diff_text = client.diff('./tmp-file-prefix-', '.')

## Determining the repository URL

    import pysvn
    client = pysvn.Client()
    entry = client.info('.')
    print 'Url:',entry.url

## Repository Tasks

This section shows examples of tasks that manipulate or examine the repository. While the common tasks schedule changes through a local working copy, these tasks affect the repository directly.

## List the contents of a repository directory

    import pysvn
    client = pysvn.Client()
    entry_list = client.ls('.')

## Get the contents of a file from the repository

    import pysvn
    client = pysvn.Client()
    file_content = client.cat('file.txt')

## Create a branch or tag

    import pysvn
    client = pysvn.Client()
    log_message = "reason for change"
    def get_log_message():
        return True, log_message
    client.callback_get_log_message = get_log_message
    client.copy('http://svnrepo.com/svn/trunk', 'http://svnrepo.com/svn/tag/%s' % tag_name )

## Move or rename files in the repository

    import pysvn
    client = pysvn.Client()
    client.move( 'file_old.txt', 'file_new.txt' )

## Lock a file

    import pysvn
    client = pysvn.Client()
    client.lock( 'file.txt', 'reason for locking' )

## Lock a file overriding another user or working copies lock

    import pysvn
    client = pysvn.Client()
    client.lock( 'file.txt', 'reason for locking', force=True )

## Unlock a file

    import pysvn
    client = pysvn.Client()
    client.unlock( 'file.txt' )

## Unlock a file locked by another user or working copy

    import pysvn
    client = pysvn.Client()
    client.unlock( 'file.txt', force=True )

## Test for a locked file

Method 1:

    all_entries = self.client.info2( path, recurse=False )
    for path, info in all_entries:
        if info['lock']:
            if info['lock']['token'] != '':
                print '%s is locked' % path
            print info['lock']['comment']

Method 2:

    all_status = self.client.status( path, recurse=False, update=True )
    for status in all_status:
        if status.entry is not None:
            if status.entry.lock_token is not None:
                print '%s is locked' % status.path

Copyright © 2004-2007 Barry A. Scott. All rigths reserved.