Index: jhbuild/modtypes/tarball.py
===================================================================
--- jhbuild/modtypes/tarball.py	(revision 1646)
+++ jhbuild/modtypes/tarball.py	(working copy)
@@ -120,6 +120,10 @@
     def do_start(self, buildscript):
         # check if jhbuild previously built it ...
         checkoutdir = self.get_builddir(buildscript)
+        if (buildscript.config.checkout_mode == 'clobber'):
+            buildscript.execute('rm -rf ' + self.get_srcdir(buildscript))
+            buildscript.packagedb.add(self.name, '')
+
         if buildscript.packagedb.check(self.name, self.version):
             return (self.STATE_DONE, None, None)
 
Index: jhbuild/versioncontrol/cvs.py
===================================================================
--- jhbuild/versioncontrol/cvs.py	(revision 1646)
+++ jhbuild/versioncontrol/cvs.py	(working copy)
@@ -27,6 +27,7 @@
 import sys
 import os
 import md5
+import distutils
 
 import git
 
@@ -223,8 +224,33 @@
         return self.revision
     branchname = property(branchname)
 
-    def _checkout(self, buildscript):
+    def _checkout_mode(self):
+        checkout_mode = self.config.checkout_mode
+        if self.config.module_checkout_mode.get(self.module) is not None:
+            checkout_mode = self.config.module_checkout_mode[self.module]
+        return checkout_mode
+    checkout_mode = property(_checkout_mode)
+
+    def _wipedir(self, buildscript):
+        if (os.path.exists(self.srcdir)):
+            buildscript.execute('rm -rf ' + self.srcdir)
+
+    def _export(self, buildscript):
         cmd = ['cvs', '-z3', '-q', '-d', self.repository.cvsroot,
+               'export']
+        if self.revision:
+            cmd.extend(['-r', self.revision])
+        else:
+            cmd.extend(['-r', 'HEAD'])
+        if self.config.sticky_date:
+            cmd.extend(['-D', self.config.sticky_date])
+        if self.checkoutdir and self.override_checkoutdir:
+            cmd.extend(['-d', self.checkoutdir])
+        cmd.append(self.module)
+        buildscript.execute(cmd, 'cvs', cwd=self.config.checkoutroot)
+
+    def _checkout(self, buildscript, copydir=None):
+        cmd = ['cvs', '-z3', '-q', '-d', self.repository.cvsroot,
                'checkout', '-P']
         if self.revision:
             cmd.extend(['-r', self.revision])
@@ -235,15 +261,23 @@
         if self.checkoutdir and self.override_checkoutdir:
             cmd.extend(['-d', self.checkoutdir])
         cmd.append(self.module)
-        buildscript.execute(cmd, 'cvs', cwd=self.checkoutroot)
+        if (copydir is not None):
+            buildscript.execute(cmd, 'cvs', cwd=copydir)
+        else:
+            buildscript.execute(cmd, 'cvs', cwd=self.config.checkoutroot)
 
-    def _update(self, buildscript):
+    def _update(self, buildscript, copydir=None):
+
         # sanity check the existing working tree:
+        if (copydir is not None):
+            outputdir = os.path.join(copydir, self.module)
+        else:
+            outputdir = self.srcdir
         try:
-            wc_root = check_root(self.srcdir)
+            wc_root = check_root(outputdir)
         except IOError:
             raise BuildStateError('"%s" does not appear to be a CVS working '
-                                  'copy' % os.path.abspath(self.srcdir))
+                                  'copy' % os.path.abspath(outputdir))
         if wc_root != self.repository.cvsroot:
             raise BuildStateError('working copy points at the wrong '
                                   'repository (expected %s but got %s). '
@@ -263,13 +297,39 @@
         if not (self.revision or self.config.sticky_date):
             cmd.append('-A')
         cmd.append('.')
-        buildscript.execute(cmd, 'cvs', cwd=self.srcdir)
+        buildscript.execute(cmd, 'cvs', cwd=outputdir)
 
+    def _copy(self, buildscript, copydir):
+
+        module = self.module
+        if self.checkoutdir and self.override_checkoutdir:
+            module = self.checkoutdir
+        fromdir = os.path.join(copydir, module)
+        todir = os.path.join(self.config.checkoutroot, module)
+        buildscript.execute('cp -R ' + fromdir + ' ' + todir)
+
     def checkout(self, buildscript):
-        if os.path.exists(self.srcdir):
-            self._update(buildscript)
-        else:
-            self._checkout(buildscript)
+        if self.checkout_mode in ('clobber', 'export'):
+            self._wipedir(buildscript)
+            if (self.checkout_mode == 'clobber'):
+                self._checkout(buildscript)
+            else:
+                self._export(buildscript)
+        elif self.checkout_mode in ('update', 'copy'):
+            copydir = None
+            if (self.checkout_mode == 'copy' and
+                self.config.copy_dir is not None):
+                copydir = self.config.copy_dir
+            else:
+                copydir = self.config.checkoutroot
+            if os.path.exists(os.path.join(copydir, self.module, 'CVS')):
+                self._update(buildscript, copydir)
+            else:
+                self._wipedir(buildscript)
+                self._checkout(buildscript, copydir)
+            if (self.checkout_mode == 'copy' and
+                self.config.copy_dir is not None):
+                self._copy(buildscript, copydir)
 
     def force_checkout(self, buildscript):
         self._checkout(buildscript)
Index: jhbuild/versioncontrol/__init__.py
===================================================================
--- jhbuild/versioncontrol/__init__.py	(revision 1646)
+++ jhbuild/versioncontrol/__init__.py	(working copy)
@@ -53,6 +53,8 @@
         for attr in self.branch_xml_attrs:
             if branchnode.hasAttribute(attr):
                 kws[attr.replace('-', '_')] = branchnode.getAttribute(attr)
+        if branchnode.hasAttribute('id'):
+            kws['branch_id'] = branchnode.getAttribute('id')
         return self.branch(name, **kws)
 
 
Index: jhbuild/versioncontrol/tarball.py
===================================================================
--- jhbuild/versioncontrol/tarball.py	(revision 1646)
+++ jhbuild/versioncontrol/tarball.py	(working copy)
@@ -52,7 +52,7 @@
                         'size', 'md5sum']
 
     def branch(self, name, version, module=None, checkoutdir=None,
-               size=None, md5sum=None):
+               size=None, md5sum=None, branch_id=None):
         if name in self.config.branches:
             module = self.config.branches[module]
         else:
@@ -63,7 +63,8 @@
             size = int(size)
         return TarballBranch(self, module=module, version=version,
                              checkoutdir=checkoutdir,
-                             source_size=size, source_md5=md5sum)
+                             source_size=size, source_md5=md5sum,
+                             branch_id=branch_id)
 
     def branch_from_xml(self, name, branchnode, repositories, default_repo):
         branch = Repository.branch_from_xml(self, name, branchnode, repositories, default_repo)
@@ -86,13 +87,14 @@
     """A class representing a Tarball."""
 
     def __init__(self, repository, module, version, checkoutdir,
-                 source_size, source_md5):
+                 source_size, source_md5, branch_id):
         Branch.__init__(self, repository, module, checkoutdir)
         self.version = version
         self.source_size = source_size
         self.source_md5 = source_md5
         self.patches = []
         self.quilt = None
+        self.branch_id = branch_id
 
     def _local_tarball(self):
         basename = os.path.basename(self.module)
@@ -209,10 +211,22 @@
                             cwd=self.srcdir,
                             extra_env={'QUILT_PATCHES' : self.quilt.srcdir})
 
+    def _checkout_mode(self):
+        checkout_mode = self.config.checkout_mode
+        if self.config.module_checkout_mode.get(self.branch_id) is not None:
+            checkout_mode = self.config.module_checkout_mode[self.branch_id]
+        return checkout_mode
+    checkout_mode = property(_checkout_mode)
+
+    def _wipedir(self, buildscript):
+        if (os.path.exists(self.srcdir)):
+            buildscript.execute('rm -rf ' + self.srcdir)
+
     def checkout(self, buildscript):
+        if self.checkout_mode == 'clobber':
+            self._wipedir(buildscript)
         if not os.path.exists(self.srcdir):
             self._download_and_unpack(buildscript)
-
         if not self.quilt is None:
             self._quilt_checkout(buildscript)
 
Index: jhbuild/versioncontrol/git.py
===================================================================
--- jhbuild/versioncontrol/git.py	(revision 1646)
+++ jhbuild/versioncontrol/git.py	(working copy)
@@ -24,6 +24,7 @@
 from stat import *
 import urlparse
 import subprocess
+import distutils
 
 from jhbuild.errors import FatalError, CommandError
 from jhbuild.utils.cmds import get_output
@@ -110,17 +111,40 @@
         raise CommandError('Command %s did not include commit line: %r'
                            % (cmd_desc, stdout))
 
-    def _checkout(self, buildscript):
+    def _checkout_mode(self):
+        checkout_mode = self.config.checkout_mode
+        if self.config.module_checkout_mode.get(os.path.basename(self.module)) is not None:
+            checkout_mode = self.config.module_checkout_mode[os.path.basename(self.module)]
+        return checkout_mode
+    checkout_mode = property(_checkout_mode)
+
+    def _wipedir(self, buildscript):
+        if (os.path.exists(self.srcdir)):
+            buildscript.execute('rm -rf ' + self.srcdir)
+
+    def _export(self, buildscript):
+        # Fixe: should implement this properly
+        self._checkout(buildscript)
+
+    def _checkout(self, buildscript, copydir = None):
+
         cmd = ['git', 'clone', self.module]
         if self.checkoutdir:
             cmd.append(self.checkoutdir)
-        buildscript.execute(cmd, 'git', cwd=self.checkoutroot)
 
+        if (copydir is not None):
+            buildscript.execute(cmd, 'git', cwd=copydir)
+        else:
+            buildscript.execute(cmd, 'git', cwd=self.config.checkoutroot)
+
         if self.config.sticky_date:
             self._update(buildscript)
 
-    def _update(self, buildscript):
-        cwd = self.get_checkoutdir()
+    def _update(self, buildscript, copydir=None):
+        if (copydir is not None):
+            cwd = os.path.join(copydir, os.path.basename(self.module))
+        else:
+            cwd = self.get_checkoutdir()
         if self.config.sticky_date:
             commit = self._get_commit_from_date()
             branch = 'jhbuild-date-branch'
@@ -135,12 +159,38 @@
                 
         buildscript.execute(['git', 'pull'], 'git', cwd=cwd)
 
+    def _copy(self, buildscript, copydir):
+         module = self.module
+         if self.checkoutdir:
+             module = self.checkoutdir
+         fromdir = os.path.join(copydir, os.path.basename(module))
+         todir = os.path.join(self.config.checkoutroot, os.path.basename(module))
+         buildscript.execute('cp -R ' + fromdir + ' ' + todir)
+
     def checkout(self, buildscript):
-        if os.path.exists(self.get_checkoutdir()):
-            self._update(buildscript)
-        else:
-            self._checkout(buildscript)
+         if self.checkout_mode in ('clobber', 'export'):
+             self._wipedir(buildscript)
+             if (self.checkout_mode == 'clobber'):
+                 self._checkout(buildscript)
+             else:
+                 self._checkout(buildscript)
+         elif self.checkout_mode in ('update', 'copy'):
+             copydir = None
+             if (self.checkout_mode == 'copy' and
+                 self.config.copy_dir is not None):
+                 copydir = self.config.copy_dir
+             else:
+                 copydir = self.config.checkoutroot
 
+             if os.path.exists(os.path.join(copydir, os.path.basename(self.module),'.git')):
+                 self._update(buildscript, copydir)
+             else:
+                 self._wipedir(buildscript)
+                 self._checkout(buildscript, copydir)
+             if (self.checkout_mode == 'copy' and
+                 self.config.copy_dir is not None):
+                 self._copy(buildscript, copydir)
+
     def tree_id(self):
         if not os.path.exists(self.get_checkoutdir()):
             return None
Index: jhbuild/versioncontrol/svn.py
===================================================================
--- jhbuild/versioncontrol/svn.py	(revision 1646)
+++ jhbuild/versioncontrol/svn.py	(working copy)
@@ -23,6 +23,7 @@
 import os
 import urlparse
 import subprocess
+import distutils.dir_util
 
 from jhbuild.errors import CommandError, BuildStateError, FatalError
 from jhbuild.utils.cmds import get_output
@@ -173,9 +174,20 @@
         return self.revision
     branchname = property(branchname)
 
-    def _checkout(self, buildscript):
-        cmd = ['svn', 'checkout', self.module]
+    def _checkout_mode(self):
+        checkout_mode = self.config.checkout_mode
+        if self.config.module_checkout_mode.get(os.path.basename(self.module)) is not None:
+            checkout_mode = self.config.module_checkout_mode[os.path.basename(self.module)]
+        return checkout_mode
+    checkout_mode = property(_checkout_mode)
 
+    def _wipedir(self, buildscript):
+        if (os.path.exists(self.srcdir)):
+            buildscript.execute('rm -rf ' + self.srcdir)
+
+    def _export(self, buildscript):
+        cmd = ['svn', 'export', self.module]
+
         if self.checkoutdir:
             cmd.append(self.checkoutdir)
 
@@ -184,18 +196,38 @@
 
         buildscript.execute(cmd, 'svn', cwd=self.checkoutroot)
     
-    def _update(self, buildscript):
+    def _checkout(self, buildscript, copydir=None):
+        cmd = ['svn', 'checkout', self.module]
+
+        if self.checkoutdir:
+            cmd.append(self.checkoutdir)
+
+        if self.config.sticky_date:
+            cmd.extend(['-r', '{%s}' % self.config.sticky_date])
+
+        if (copydir is not None):
+            buildscript.execute(cmd, 'svn', cwd=copydir)
+        else:
+            buildscript.execute(cmd, 'svn', cwd=self.config.checkoutroot)
+
+    def _update(self, buildscript, copydir=None):
         opt = []
+        if (copydir is not None):
+            outputdir = os.path.join(copydir, os.path.basename(self.module))
+        else:
+            outputdir = self.srcdir
+
+        opt = []
         if self.config.sticky_date:
             opt.extend(['-r', '{%s}' % self.config.sticky_date])
 
         # if the URI doesn't match, use "svn switch" instead of "svn update"
-        if get_uri(self.srcdir) != self.module:
+        if get_uri(outputdir) != self.module:
             cmd = ['svn', 'switch'] + opt + [self.module]
         else:
             cmd = ['svn', 'update'] + opt + ['.']
 
-        buildscript.execute(cmd, 'svn', cwd=self.srcdir)
+        buildscript.execute(cmd, 'svn', cwd=outputdir)
 
         try:
             self._check_for_conflicts()
@@ -204,6 +236,15 @@
             buildscript.execute(['svn', 'status'], 'svn', cwd=self.srcdir)
             raise
 
+    def _copy(self, buildscript, copydir):
+
+        module = self.module
+        if self.checkoutdir:
+            module = self.checkoutdir
+        fromdir = os.path.join(copydir, os.path.basename(module))
+        todir = os.path.join(self.config.checkoutroot, os.path.basename(module))
+        buildscript.execute('cp -R ' + fromdir + ' ' + todir)
+
     def _check_for_conflicts(self):
         kws = {}
         kws['cwd'] = self.srcdir
@@ -222,11 +263,29 @@
             raise CommandError('Error checking for conflicts')
 
     def checkout(self, buildscript):
-        if os.path.exists(self.srcdir):
-            self._update(buildscript)
-        else:
-            self._checkout(buildscript)
+        if self.checkout_mode in ('clobber', 'export'):
+            self._wipedir(buildscript)
+            if (self.checkout_mode == 'clobber'):
+                self._checkout(buildscript)
+            else:
+                self._export(buildscript)
+        elif self.checkout_mode in ('update', 'copy'):
+            copydir = None
+            if (self.checkout_mode == 'copy' and
+                self.config.copy_dir is not None):
+                copydir = self.config.copy_dir
+            else:
+                copydir = self.config.checkoutroot
 
+            if os.path.exists(os.path.join(copydir, os.path.basename(self.module),'.svn')):
+                self._update(buildscript, copydir)
+            else:
+                self._wipedir(buildscript)
+                self._checkout(buildscript, copydir)
+            if (self.checkout_mode == 'copy' and
+                self.config.copy_dir is not None):
+                self._copy(buildscript, copydir)
+
     def force_checkout(self, buildscript):
         self._checkout(buildscript)
 
Index: jhbuild/config.py
===================================================================
--- jhbuild/config.py	(revision 1646)
+++ jhbuild/config.py	(working copy)
@@ -36,7 +36,8 @@
                 'alwaysautogen', 'nobuild', 'makeclean', 'makecheck',
                 'use_lib64', 'tinderbox_outputdir', 'sticky_date',
                 'tarballdir', 'pretty_print', 'svn_program', 'makedist',
-                'makedistcheck', 'nonotify', 'cvs_program' ]
+                'makedistcheck', 'nonotify', 'cvs_program',
+                'checkout_mode', 'copy_dir', 'module_checkout_mode']
 
 env_prepends = {}
 def prependpath(envvar, path):
Index: jhbuild/defaults.jhbuildrc
===================================================================
--- jhbuild/defaults.jhbuildrc	(revision 1646)
+++ jhbuild/defaults.jhbuildrc	(working copy)
@@ -48,6 +48,15 @@
 
 interact      = True   # whether to interact with the user.
 
+# checkout modes. For VCS directories, it specifies how the checkout
+# is done. We can also specify checkout modes for specific modules
+checkout_mode = 'update'
+module_checkout_mode = {}
+
+# in case we use the copy checkout mode, we can set up a copy dir. Defaults to
+# checkout dir
+copy_dir = None
+
 # whether to install to lib64 directories?  Currently this will default to
 # True on Linux AMD64, PPC64 or S390x systems, and False everywhere else.
 # Patches accepted to fix the default for other architectures.
