diff --git a/product/ERP5/Document/BusinessTemplate.py b/product/ERP5/Document/BusinessTemplate.py
index b9273d13b3b84c52e288246bb5f7bbdc70aa3ee4..4ab62b0cab025658169d34c50d80ca61a48bd2dd 100644
--- a/product/ERP5/Document/BusinessTemplate.py
+++ b/product/ERP5/Document/BusinessTemplate.py
@@ -85,6 +85,8 @@ import posixpath
 import transaction
 
 import threading
+from Products.ERP5.genbt5list import BusinessTemplateRevision, \
+  item_name_list, item_set
 
 CACHE_DATABASE_PATH = None
 try:
@@ -306,6 +308,7 @@ class BusinessTemplateArchive(object):
   """
   def __init__(self, path, **kw):
     self.path = path
+    self.revision = BusinessTemplateRevision()
 
   def addObject(self, obj, name, path=None, ext='.xml'):
     if path:
@@ -320,15 +323,23 @@ class BusinessTemplateArchive(object):
       if not isinstance(obj, str):
         obj.seek(0)
         obj = obj.read()
+      self.revision.hash(path, obj)
       self._writeString(obj, path)
     else:
       if isinstance(obj, str):
+        self.revision.hash(path, obj)
         obj = StringIO(obj)
+      else:
+        obj.seek(0)
+        self.revision.hash(path, obj.read())
       write(obj, path)
 
   def finishCreation(self):
     pass
 
+  def getRevision(self):
+    return self.revision.digest()
+
 class BusinessTemplateFolder(BusinessTemplateArchive):
   """
     Class archiving business template into a folder tree
@@ -348,9 +359,8 @@ class BusinessTemplateFolder(BusinessTemplateArchive):
       Import file from a local folder
     """
     join = os.path.join
-    path = os.path.normpath(self.path)
-    class_name = item.__class__.__name__
-    root = join(path, class_name, '')
+    item_name = item.__class__.__name__
+    root = join(os.path.normpath(self.path), item_name, '')
     root_path_len = len(root)
     if CACHE_DATABASE_PATH:
       try:
@@ -362,9 +372,13 @@ class BusinessTemplateFolder(BusinessTemplateArchive):
         for file_name in files:
           file_name = join(root, file_name)
           with open(file_name, 'rb') as f:
-            file_name = file_name[root_path_len:]
+            file_name = posixpath.normpath(file_name[root_path_len:])
             if '%' in file_name:
               file_name = unquote(file_name)
+            elif item_name == 'bt' and file_name == 'revision':
+              continue
+            self.revision.hash(item_name + '/' + file_name, f.read())
+            f.seek(0)
             item._importFile(file_name, f)
     finally:
       if hasattr(cache_database, 'db'):
@@ -411,10 +425,16 @@ class BusinessTemplateTarball(BusinessTemplateArchive):
       Import all file from the archive to the site
     """
     extractfile = self.tar.extractfile
-    for file_name, info in self.item_dict.get(item.__class__.__name__, ()):
+    item_name = item.__class__.__name__
+    for file_name, info in self.item_dict.get(item_name, ()):
       if '%' in file_name:
         file_name = unquote(file_name)
-      item._importFile(file_name, extractfile(info))
+      elif item_name == 'bt' and file_name == 'revision':
+        continue
+      f = extractfile(info)
+      self.revision.hash(item_name + '/' + file_name, f.read())
+      f.seek(0)
+      item._importFile(file_name, f)
 
 class TemplateConditionError(Exception): pass
 class TemplateConflictError(Exception): pass
@@ -4782,63 +4802,6 @@ Business Template is a set of definitions, such as skins, portal types and categ
          , 'filter_content_types' : 1
       }
 
-    # This is a global variable
-    # Order is important for installation
-    # We want to have:
-    #  * path after module, because path can be module content
-    #  * path after categories, because path can be categories content
-    #  * path after portal types roles so that roles in the current bt can be used
-    #  * path before workflow chain, because path can be a portal type
-    #         (until chains are set on portal types with categories)
-    #  * skin after paths, because we can install a custom connection string as
-    #       path and use it with SQLMethods in a skin.
-    #    ( and more )
-    _item_name_list = [
-      '_registered_version_priority_selection_item',
-      '_product_item',
-      '_document_item',
-      '_property_sheet_item',
-      '_constraint_item',
-      '_extension_item',
-      '_test_item',
-      '_role_item',
-      '_tool_item',
-      '_message_translation_item',
-      '_workflow_item',
-      '_site_property_item',
-      '_portal_type_item',
-      #'_portal_type_workflow_chain_item',
-      '_portal_type_allowed_content_type_item',
-      '_portal_type_hidden_content_type_item',
-      '_portal_type_property_sheet_item',
-      '_portal_type_base_category_item',
-      '_category_item',
-      '_module_item',
-      '_portal_type_roles_item',
-      '_path_item',
-      '_skin_item',
-      '_registered_skin_selection_item',
-      '_preference_item',
-      '_action_item',
-      '_local_roles_item',
-      '_portal_type_workflow_chain_item',
-      '_catalog_method_item',
-      '_catalog_result_key_item',
-      '_catalog_related_key_item',
-      '_catalog_result_table_item',
-      '_catalog_search_key_item',
-      '_catalog_keyword_key_item',
-      '_catalog_datetime_key_item',
-      '_catalog_full_text_key_item',
-      '_catalog_request_key_item',
-      '_catalog_multivalue_key_item',
-      '_catalog_topic_key_item',
-      '_catalog_scriptable_key_item',
-      '_catalog_role_key_item',
-      '_catalog_local_role_key_item',
-      '_catalog_security_uid_column_item',
-    ]
-
     def __init__(self, *args, **kw):
       XMLObject.__init__(self, *args, **kw)
       self._clean()
@@ -4870,23 +4833,10 @@ Business Template is a set of definitions, such as skins, portal types and categ
           self.workflow_history[
                             'business_template_installation_workflow'] = None
 
-    security.declareProtected(Permissions.AccessContentsInformation,
-                              'getRevision')
-    def getRevision(self):
-      """returns the revision property.
-      This is a workaround for #461.
-      """
-      return self._baseGetRevision()
-
-    def updateRevisionNumber(self):
-        """Increment bt revision number.
-        """
-        revision_number = self.getRevision()
-        if revision_number is None or revision_number.strip() == '':
-          revision_number = 1
-        else:
-          revision_number = int(revision_number)+1
-        self.setRevision(revision_number)
+    def getShortRevision(self):
+      """Returned a shortened revision"""
+      r = self.getRevision()
+      return r and r[:5]
 
     security.declareProtected(Permissions.ManagePortal, 'storeTemplateItemData')
     def storeTemplateItemData(self):
@@ -5009,7 +4959,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
         pass
 
     security.declareProtected(Permissions.ManagePortal, 'build')
-    def build(self, no_action=0):
+    def build(self, no_action=0, update_revision=True):
       """
         Copy existing portal objects to self
       """
@@ -5018,19 +4968,11 @@ Business Template is a set of definitions, such as skins, portal types and categ
       # Make sure that everything is sane.
       self.clean()
 
-      try:
-        from Products.ERP5VCS.WorkingCopy import NotAWorkingCopyError
-        try:
-          self.setRevision(self.getVcsTool().newRevision())
-        except NotAWorkingCopyError:
-          raise ImportError
-      except ImportError:
-        self.updateRevisionNumber()
       self._setTemplateFormatVersion(1)
       self.storeTemplateItemData()
 
       # Build each part
-      for item_name in self._item_name_list:
+      for item_name in item_name_list:
         item = getattr(self, item_name)
         if item is None:
           continue
@@ -5039,6 +4981,8 @@ Business Template is a set of definitions, such as skins, portal types and categ
         item.build(self)
       # update _p_jar property of objects cleaned by removeProperties
       transaction.savepoint(optimistic=True)
+      if update_revision:
+        self._export()
 
     def publish(self, url, username=None, password=None):
       """
@@ -5118,14 +5062,14 @@ Business Template is a set of definitions, such as skins, portal types and categ
         return modified_object_list
       elif installed_bt_format == 0 and new_bt_format == 1:
         # return list of all object in bt
-        for item_name in self._item_name_list:
+        for item_name in item_name_list:
           item = getattr(self, item_name, None)
           if item is not None:
             for path in item._objects.keys():
               modified_object_list.update({path : ['New', item.__class__.__name__[:-12]]})
         return modified_object_list
 
-      for item_name in self._item_name_list:
+      for item_name in item_name_list:
         new_item = getattr(self, item_name, None)
         installed_item = getattr(installed_bt, item_name, None)
         if new_item is not None:
@@ -5186,7 +5130,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
 
       # Install everything
       if len(object_to_update) or force:
-        for item_name in self._item_name_list:
+        for item_name in item_name_list:
           item = getattr(self, item_name, None)
           if item is not None:
             item.install(self, force=force, object_to_update=object_to_update, 
@@ -5211,7 +5155,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
       # remove object from old business template
       if len(remove_object_dict):
         # XXX: this code assumes that there is an installed_bt
-        for item_name in reversed(installed_bt._item_name_list):
+        for item_name in reversed(item_name_list):
           item = getattr(installed_bt, item_name, None)
           if item is not None:
             item.remove(self, remove_object_dict=remove_object_dict, trashbin=trashbin)
@@ -5255,7 +5199,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
         not remove all items.
       """
       # Trash everything
-      for item_name in self._item_name_list[::-1]:
+      for item_name in reversed(item_name_list):
         item = getattr(self, item_name, None)
         if item is not None:
           item.trash(
@@ -5268,7 +5212,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
       """
       # Uninstall everything
       # Trash everything
-      for item_name in self._item_name_list[::-1]:
+      for item_name in reversed(item_name_list):
         item = getattr(self, item_name, None)
         if item is not None:
           item.uninstall(self, **kw)
@@ -5296,7 +5240,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
         if hasattr(self, attr):
           delattr(self, attr)
       # Secondly, make attributes empty.
-      for item_name in self._item_name_list:
+      for item_name in item_name_list:
         setattr(self, item_name, None)
 
     security.declareProtected(Permissions.ManagePortal, 'clean')
@@ -5558,7 +5502,9 @@ Business Template is a set of definitions, such as skins, portal types and categ
       if self.getBuildingState() != 'built':
         raise TemplateConditionError, \
               'Business Template must be built before export'
+      return self._export(path, local, bta)
 
+    def _export(self, path=None, local=0, bta=None):
       if bta is None:
         if local:
           # we export into a folder tree
@@ -5573,7 +5519,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
       for prop in self.propertyMap():
         prop_type = prop['type']
         id = prop['id']
-        if id in ('id', 'uid', 'rid', 'sid', 'id_group', 'last_id',
+        if id in ('id', 'uid', 'rid', 'sid', 'id_group', 'last_id', 'revision',
                   'install_object_list_list', 'id_generator', 'bt_for_diff'):
           continue
         value = self.getProperty(id)
@@ -5585,11 +5531,12 @@ Business Template is a set of definitions, such as skins, portal types and categ
           bta.addObject('\n'.join(value), name=id, path='bt', ext='')
 
       # Export each part
-      for item_name in self._item_name_list:
+      for item_name in item_name_list:
         item = getattr(self, item_name, None)
         if item is not None:
           item.export(context=self, bta=bta)
 
+      self._setRevision(bta.getRevision())
       return bta.finishCreation()
 
     security.declareProtected(Permissions.ManagePortal, 'importFile')
@@ -5630,7 +5577,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
           setattr(module, template_id, type(template_id,
             (SimpleItem.SimpleItem,), {'__module__': module_id}))
 
-      for item_name in self._item_name_list:
+      for item_name in item_name_list:
         item_object = getattr(self, item_name, None)
         # this check is due to backwards compatability when there can be a
         # difference between install erp5_property_sheets (esp. BusinessTemplate
@@ -5643,11 +5590,13 @@ Business Template is a set of definitions, such as skins, portal types and categ
       for module_id in module_id_list:
         del sys.modules[module_id]
 
+      self._setRevision(bta.getRevision())
+
     def getItemsList(self):
       """Return list of items in business template
       """
       items_list = []
-      for item_name in self._item_name_list:
+      for item_name in item_name_list:
         item = getattr(self, item_name, None)
         if item is not None:
           items_list.extend(item.getKeys())
@@ -6106,5 +6055,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
 
 # Block acquisition on all _item_name_list properties by setting
 # a default class value to None
-for key in BusinessTemplate._item_name_list:
+for key in item_name_list:
   setattr(BusinessTemplate, key, None)
+# Check naming convention of items.
+assert item_set.issubset(globals()), item_set.difference(globals())
diff --git a/product/ERP5/Tool/TemplateTool.py b/product/ERP5/Tool/TemplateTool.py
index 2a337b9b2136abe87c255096b20d1a899b234132..439291d5dff6c43f53625fcb62af1755c2e45857 100644
--- a/product/ERP5/Tool/TemplateTool.py
+++ b/product/ERP5/Tool/TemplateTool.py
@@ -44,6 +44,7 @@ from Products.ERP5Type.Tool.BaseTool import BaseTool
 from Products.ERP5Type.Cache import transactional_cached
 from Products.ERP5Type import Permissions
 from Products.ERP5.Document.BusinessTemplate import BusinessTemplateMissingDependency
+from Products.ERP5.genbt5list import generateInformation
 from Acquisition import aq_base
 from tempfile import mkstemp, mkdtemp
 from Products.ERP5 import _dtmldir
@@ -124,23 +125,19 @@ class TemplateTool (BaseTool):
       # However, that unlikely happens, and using a Z SQL Method has a
       # potential danger because business templates may exchange catalog
       # methods, so the database could be broken temporarily.
-      latest_bt = None
-      latest_revision = 0
-      for bt in self.contentValues(filter={'portal_type':'Business Template'}):
+      last_bt = last_time = None
+      for bt in self.objectValues(portal_type='Business Template'):
         if bt.getTitle() == title or title in bt.getProvisionList():
-          installation_state = bt.getInstallationState()
-          if installation_state == 'installed':
-            latest_bt = bt
-            break
-          elif strict is False and installation_state == 'replaced':
-            revision = bt.getRevision()
-            try:
-              revision = int(revision)
-            except ValueError:
-              continue
-            if revision > latest_revision:
-              latest_bt = bt
-      return latest_bt
+          state = bt.getInstallationState()
+          if state == 'installed':
+            return bt
+          if state == 'replaced' and not strict:
+            t = bt.workflow_history \
+              ['business_template_installation_workflow'][-1]['time']
+            if last_time < t:
+              last_bt = bt
+              last_time = t
+      return last_bt
 
     def getInstalledBusinessTemplatesList(self):
       """Deprecated.
@@ -180,20 +177,12 @@ class TemplateTool (BaseTool):
         return bt.getRevision()
       return None
 
-    def getBuiltBusinessTemplatesList(self):
-      """Deprecated.
-      """
-      DeprecationWarning('getBuiltBusinessTemplatesList is deprecated; Use getBuiltBusinessTemplateList instead.', DeprecationWarning)
-      return self.getBuiltBusinessTemplateList()
-
     def getBuiltBusinessTemplateList(self):
       """Get the list of built and not installed business templates.
       """
-      built_bts = []
-      for bt in self.contentValues(portal_type='Business Template'):
-        if bt.getInstallationState() == 'not_installed' and bt.getBuildingState() == 'built':
-          built_bts.append(bt)
-      return built_bts
+      return [bt for bt in self.objectValues(portal_type='Business Template')
+                 if bt.getInstallationState() == 'not_installed' and
+                    bt.getBuildingState() == 'built']
 
     @property
     def asRepository(self):
@@ -201,7 +190,7 @@ class TemplateTool (BaseTool):
         """Export business template by their title
 
         Provides a view of template tool allowing a user to download the last
-        revision of a business template with a URL like:
+        edited business template with a URL like:
           http://.../erp5/portal_templates/asRepository/erp5_core
         """
         def __before_publishing_traverse__(self, self2, request):
@@ -213,9 +202,9 @@ class TemplateTool (BaseTool):
           last_bt = None, None
           for bt in self.aq_parent.searchFolder(title=title):
             bt = bt.getObject()
-            revision = int(bt.getRevision())
-            if last_bt[0] < revision and bt.getInstallationState() != 'deleted':
-              last_bt = revision, bt
+            modified = bt.getModificationDate()
+            if last_bt[0] < modified and bt.getInstallationState() != 'deleted':
+              last_bt = modified, bt
           if last_bt[1] is None:
             return RESPONSE.notFoundError(title)
           RESPONSE.setHeader('Content-type', 'application/data')
@@ -342,18 +331,6 @@ class TemplateTool (BaseTool):
       finally:
         shutil.rmtree(svn_checkout_tmp_dir)
 
-    def assertBtPathExists(self, url):
-      """
-      Check if bt is present on the system
-      """
-      urltype, name = splittype(url)
-      # Windows compatibility
-      if WIN:
-        if os.path.isdir(os.path.normpath(url)) or \
-           os.path.isfile(os.path.normpath(url)):
-          name = os.path.normpath(url)
-      return os.path.exists(os.path.normpath(name))
-
     security.declareProtected( 'Import/Export objects', 'download' )
     def download(self, url, id=None, REQUEST=None):
       """
@@ -368,13 +345,9 @@ class TemplateTool (BaseTool):
         id = self.generateNewId()
 
       urltype, name = splittype(url)
-      # Windows compatibility
-      if WIN:
-        if os.path.isdir(os.path.normpath(url)) or \
-           os.path.isfile(os.path.normpath(url)):
-          urltype = 'file'
-          name = os.path.normpath(url)
-
+      if WIN and urltype and '\\' in name:
+        urltype = None
+        name = url
       if urltype and urltype != 'file':
         if '/portal_templates/asRepository/' in url:
           # In this case, the downloaded BT is already built.
@@ -384,7 +357,7 @@ class TemplateTool (BaseTool):
           return self[self._setObject(id, bt)]
         bt = self._download_url(url, id)
       else:
-        bt = self._download_local(name, id)
+        bt = self._download_local(os.path.normpath(name), id)
 
       bt.build(no_action=True)
       return bt
@@ -592,9 +565,12 @@ class TemplateTool (BaseTool):
                                'updateRepositoryBusinessTemplateList' )
 
     def updateRepositoryBusinessTemplateList(self, repository_list,
-                                             REQUEST=None, RESPONSE=None, **kw):
+        REQUEST=None, RESPONSE=None, genbt5list=0, **kw):
       """
         Update the information on Business Templates from repositories.
+
+      For local repositories, if bt5list is missing or if genbt5list > 1,
+      bt5list is automatically generated (but not saved on disk).
       """
       self.repository_dict = PersistentMapping()
       property_list = ('title', 'version', 'revision', 'description', 'license',
@@ -602,9 +578,19 @@ class TemplateTool (BaseTool):
       #LOG('updateRepositoryBusiessTemplateList', 0,
       #    'repository_list = %r' % (repository_list,))
       for repository in repository_list:
-        url = '/'.join([repository, 'bt5list'])
-        f = urlopen(url)
-        property_dict_list = []
+        urltype, url = splittype(repository)
+        if WIN and urltype and '\\' in url:
+          urltype = None
+          url = repository
+        if urltype and urltype != 'file':
+          f = urlopen(repository + '/bt5list')
+        else:
+          bt5list = os.path.join(url, 'bt5list')
+          if genbt5list > os.path.exists(bt5list):
+            f = generateInformation(url)
+            f.seek(0)
+          else:
+            f = open(bt5list, 'rb')
         try:
           try:
             doc = parse(f)
@@ -618,6 +604,7 @@ class TemplateTool (BaseTool):
             else:
               raise RuntimeError, 'Invalid repository: %s' % repository
           try:
+            property_dict_list = []
             root = doc.documentElement
             for template in root.getElementsByTagName("template"):
               id = template.getAttribute('id')
@@ -958,9 +945,6 @@ class TemplateTool (BaseTool):
          update_only: return only bt that needs to be updated
          template_list: only returns bt within the given list
       """
-      version_state_title_dict = { 'new' : 'New', 'present' : 'Present',
-                                   'old' : 'Old' }
-
       from Products.ERP5Type.Document import newTempBusinessTemplate
       result_list = []
       template_set = None
@@ -987,15 +971,9 @@ class TemplateTool (BaseTool):
               # if this business template is newer.
               previous_repository, previous_property_dict = \
                   template_item_dict[title]
-              diff_version = self.compareVersions(previous_property_dict['version'],
-                                                  property_dict['version'])
-              if diff_version < 0:
+              if self.compareVersions(previous_property_dict['version'],
+                                      property_dict['version']) < 0:
                 template_item_dict[title] = (repository, property_dict)
-              elif diff_version == 0 \
-                   and previous_property_dict['revision'] \
-                   and property_dict['revision'] \
-                   and int(previous_property_dict['revision']) < int(property_dict['revision']):
-                      template_item_dict[title] = (repository, property_dict)
       # Next, select only updated business templates.
       if update_only:
         for repository, property_dict in template_item_dict.values():
@@ -1007,9 +985,8 @@ class TemplateTool (BaseTool):
             if diff_version < 0:
               template_item_list.append((repository, property_dict))
             elif diff_version == 0 \
-                  and installed_bt.getRevision() \
                   and property_dict['revision'] \
-                  and int(installed_bt.getRevision()) < int(property_dict['revision']):
+                  and installed_bt.getRevision() != property_dict['revision']:
                     template_item_list.append((repository, property_dict))
           elif template_list is not None:
             template_item_list.append((repository, property_dict))
@@ -1017,29 +994,24 @@ class TemplateTool (BaseTool):
       # Create temporary Business Template objects for displaying.
       for repository, property_dict in template_item_list:
         property_dict = property_dict.copy()
-        id = property_dict['id']
-        filename = property_dict['id']
-        del property_dict['id']
-        revision = property_dict['revision']
-        version_state = 'new'
+        id = filename = property_dict.pop('id')
         installed_bt = \
             self.getInstalledBusinessTemplate(property_dict['title'])
         if installed_bt is not None:
           installed_version = installed_bt.getVersion()
-          installed_revision = installed_bt.getRevision()
-          result = self.compareVersions(installed_revision, revision)
-          if result == 0:
+          installed_revision = installed_bt.getShortRevision()
+          if installed_bt.getRevision() == property_dict['revision']:
             version_state = 'present'
-          elif result < 0:
-            version_state = 'old'
+          else:
+            version_state = 'different'
         else:
           installed_version = ''
           installed_revision = ''
-        version_state_title = version_state_title_dict[version_state]
+          version_state = 'new'
         uid = self.encodeRepositoryBusinessTemplateUid(repository, id)
         obj = newTempBusinessTemplate(self, 'temp_' + uid,
                                       version_state = version_state,
-                                      version_state_title = version_state_title,
+                                      version_state_title=version_state.title(),
                                       filename = filename,
                                       installed_version = installed_version,
                                       installed_revision = installed_revision,
@@ -1104,10 +1076,9 @@ class TemplateTool (BaseTool):
 
       return 0
 
-    def _getBusinessTemplateUrlDict(self, newest_only=False):
+    def _getBusinessTemplateUrlDict(self):
       business_template_url_dict = {}
-      for bt in self.getRepositoryBusinessTemplateList(\
-                                    newest_only=newest_only):
+      for bt in self.getRepositoryBusinessTemplateList():
         url, name = self.decodeRepositoryBusinessTemplateUid(bt.getUid())
         if name.endswith('.bt5'):
           name = name[:-4]
@@ -1119,14 +1090,11 @@ class TemplateTool (BaseTool):
 
     security.declareProtected(Permissions.ManagePortal,
         'installBusinessTemplatesFromRepositories')
-    def installBusinessTemplatesFromRepositories(self, template_list,
-        only_newer=True, update_catalog=_MARKER, activate=False,
-        install_dependency=False):
+    def installBusinessTemplatesFromRepositories(self, *args, **kw):
       """Deprecated.
       """
       DeprecationWarning('installBusinessTemplatesFromRepositories is deprecated; Use self.installBusinessTemplateListFromRepository instead.', DeprecationWarning)
-      return self.installBusinessTemplateListFromRepository(template_list,
-        only_newer, update_catalog, activate, install_dependency)
+      return self.installBusinessTemplateListFromRepository(*args, **kw)
 
     security.declareProtected(Permissions.ManagePortal,
          'resolveBusinessTemplateListDependency')
@@ -1187,7 +1155,7 @@ class TemplateTool (BaseTool):
     security.declareProtected(Permissions.ManagePortal,
         'installBusinessTemplateListFromRepository')
     def installBusinessTemplateListFromRepository(self, template_list,
-        only_newer=True, update_catalog=_MARKER, activate=False,
+        only_different=True, update_catalog=_MARKER, activate=False,
         install_dependency=False):
       """Installs template_list from configured repositories by default only newest"""
       # XXX-Luke: This method could replace
@@ -1197,12 +1165,13 @@ class TemplateTool (BaseTool):
       operation_log = []
       resolved_template_list = self.resolveBusinessTemplateListDependency(
                    template_list)
-
-      installed_bt5_set = set([x.title
-                               for x in self.getInstalledBusinessTemplatesList()])
+      installed_bt5_dict = dict((x.getTitle(), x.getRevision())
+        for x in self.getInstalledBusinessTemplateList())
+      if only_different:
+        template_url_dict = self._getBusinessTemplateUrlDict()
 
       def checkAvailability(bt_title):
-        return bt_title in template_list or bt_title in installed_bt5_set
+        return bt_title in template_list or bt_title in installed_bt5_dict
       missing_dependency_list = [i for i in resolved_template_list
                                  if not checkAvailability(i[1].replace(".bt5", ""))]
 
@@ -1211,17 +1180,14 @@ class TemplateTool (BaseTool):
             "Impossible to install, please install the following dependencies before: %s" \
             % [x[1] for x in missing_dependency_list]
 
-      template_url_dict = self._getBusinessTemplateUrlDict()
       activate_kw =  dict(activity="SQLQueue", tag="start_%s" % (time.time()))
       for repository, bt_id in resolved_template_list:
-        bt = template_url_dict.get(bt_id)
-        if bt is not None and bt_id in installed_bt5_set:
-          revision = int(bt['revision'])
-          installed_bt5 = self.getInstalledBusinessTemplate(bt_id)
-          if int(installed_bt5.getRevision()) <= revision and only_newer:
+        if only_different:
+          bt = template_url_dict.get(bt_id)
+          if bt is not None and bt['revision'] == installed_bt5_dict.get(bt_id):
             continue
         bt_url = '%s/%s' % (repository, bt_id)
-        param_dict = dict(download_url=bt_url, only_newer=only_newer)
+        param_dict = dict(download_url=bt_url, only_different=only_different)
         if update_catalog is not _MARKER:
           param_dict["update_catalog"] = update_catalog
 
@@ -1234,7 +1200,7 @@ class TemplateTool (BaseTool):
         else:
           document = self.updateBusinessTemplateFromUrl(**param_dict)
           operation_log.append('Installed %s with revision %s' % (
-              document.getTitle(), document.getRevision()))
+              document.getTitle(), document.getShortRevision()))
 
       return operation_log
 
@@ -1248,7 +1214,7 @@ class TemplateTool (BaseTool):
                                          reinstall=False,
                                          active_process=None,
                                          force_keep_list=None,
-                                         only_newer=True):
+                                         only_different=True):
       """
         This method download and install a bt5, from a URL.
 
@@ -1284,18 +1250,13 @@ class TemplateTool (BaseTool):
       if reinstall:
         install_kw = None
       else:
-        previous_bt5 = self.getInstalledBusinessTemplate(bt_title)
-        if (previous_bt5 is not None) and only_newer:
-          try:
-            imported_revision = int(imported_bt5.getRevision())
-            previous_revision = int(previous_bt5.getRevision())
-            if imported_revision <= previous_revision:
-              log("%s is already installed with revision %i, which is same or "
-                  "newer revision than new revision %i." % (bt_title,
-                    previous_revision, imported_revision))
-              return imported_bt5
-          except ValueError:
-            pass
+        if only_different:
+          previous_bt5 = self.getInstalledBusinessTemplate(bt_title)
+          if previous_bt5 and \
+             imported_bt5.getRevision() == previous_bt5.getRevision():
+            log("%s is already installed with revision %s"
+                % (bt_title, imported_bt5.getShortRevision()))
+            return imported_bt5
 
         install_kw = {}
         for listbox_line in imported_bt5.BusinessTemplate_getModifiedObject():
diff --git a/product/ERP5/bin/genbt5list b/product/ERP5/bin/genbt5list
index f3367044f986f77fba1f1b1252552253d2926f82..2608602dc4798c860f9ade53fcb72b6fbab878a9 100755
--- a/product/ERP5/bin/genbt5list
+++ b/product/ERP5/bin/genbt5list
@@ -31,59 +31,147 @@
 """Generate repository information on Business Templates.
 """
 
+import posixpath
 import tarfile
 import os
 import sys
 import cgi
+from base64 import b64encode
 from cStringIO import StringIO
+from hashlib import sha1
+from urllib import unquote
 
-property_list = '''
+
+# Order is important for installation
+# We want to have:
+#  * path after module, because path can be module content
+#  * path after categories, because path can be categories content
+#  * path after portal types roles so that roles in the current bt can be used
+#  * path before workflow chain, because path can be a portal type
+#         (until chains are set on portal types with categories)
+#  * skin after paths, because we can install a custom connection string as
+#       path and use it with SQLMethods in a skin.
+#    ( and more )
+item_name_list = (
+  'registered_version_priority_selection',
+  'product',
+  'document',
+  'property_sheet',
+  'constraint',
+  'extension',
+  'test',
+  'role',
+  'tool',
+  'message_translation',
+  'workflow',
+  'site_property',
+  'portal_type',
+  'portal_type_allowed_content_type',
+  'portal_type_hidden_content_type',
+  'portal_type_property_sheet',
+  'portal_type_base_category',
+  'category',
+  'module',
+  'portal_type_roles',
+  'path',
+  'skin',
+  'registered_skin_selection',
+  'preference',
+  'action',
+  'local_roles',
+  'portal_type_workflow_chain',
+  'catalog_method',
+  'catalog_result_key',
+  'catalog_related_key',
+  'catalog_result_table',
+  'catalog_search_key',
+  'catalog_keyword_key',
+  'catalog_datetime_key',
+  'catalog_full_text_key',
+  'catalog_request_key',
+  'catalog_multivalue_key',
+  'catalog_topic_key',
+  'catalog_scriptable_key',
+  'catalog_role_key',
+  'catalog_local_role_key',
+  'catalog_security_uid_column',
+)
+
+item_set = set(('CatalogDateTimeKey' if x == 'catalog_datetime_key' else
+             ''.join(map(str.title, x.split('_')))) + 'TemplateItem'
+            for x in item_name_list)
+item_set.add('bt')
+item_name_list = tuple('_%s_item' % x for x in item_name_list)
+
+class BusinessTemplateRevision(list):
+
+  def hash(self, path, text):
+    self.append((path, sha1(text).digest()))
+
+  def digest(self):
+    self.sort()
+    return b64encode(sha1('\0'.join(h + p for (h, p) in self)).digest())
+
+
+class BusinessTemplate(dict):
+
+  property_list = frozenset('''
 title
 version
-revision
 description
 license
 dependency_list
 provision_list
 copyright_list
-'''.split()
+'''.split())
 
-bt_title_path = os.path.join('bt', 'title')
+  def __init__(self):
+    self.revision = BusinessTemplateRevision()
 
-def readProperty(property_dict, property_name, property_file):
+  def _read(self, path, file):
     try:
-      text = property_file.read()
-      if property_name.endswith('_list'):
-        property_dict[property_name[:-5]] = text.splitlines()
-      else:
-        property_dict[property_name] = text
+      text = file.read()
     finally:
-      property_file.close()
-
-def readBusinessTemplate(tar):
-  """Read an archived Business Template info.
-  """
-  property_dict = {}
-  for info in tar:
-    name_list = info.name.split('/')
-    if len(name_list) == 3 and name_list[1] == 'bt' and name_list[2] in property_list:
-      property_file = tar.extractfile(info)
-      property_name = name_list[2]
-      readProperty(property_dict, property_name, property_file)
-
-  return property_dict
-
-def readBusinessTemplateDirectory(dir):
-  """Read Business Template Directory info.
-  """
-  property_dict = {}
-  for property_name in property_list:
-    filename = os.path.join(dir, 'bt', property_name)
-    if os.path.isfile(filename):
-      property_file = open(filename, 'rb')
-      readProperty(property_dict, property_name, property_file)
-
-  return property_dict
+      file.close()
+    if path.startswith('bt/'):
+      name = path[3:]
+      if name in self.property_list:
+        if name.endswith('_list'):
+          self[name[:-5]] = text.splitlines()
+        else:
+          self[name] = text
+      elif name == 'revision':
+        return
+    self.revision.hash(unquote(path) if '%' in path else path, text)
+
+  def __iter__(self):
+    self['revision'] = self.revision.digest()
+    return iter(sorted(self.iteritems()))
+
+  @classmethod
+  def fromTar(cls, tar):
+    """Read an archived Business Template info"""
+    self = cls()
+    for info in tar:
+      if not info.isdir():
+        name = info.name.split('/', 1)[1]
+        if name.split('/', 1)[0] in item_set:
+          self._read(name, tar.extractfile(info))
+    return iter(self)
+
+  @classmethod
+  def fromDir(cls, dir):
+    """Read Business Template Directory info"""
+    self = cls()
+    lstrip_len = len(dir + os.sep)
+    for root, dirs, files in os.walk(dir):
+      if root:
+        for path in files:
+          path = os.path.join(root, path)
+          self._read(posixpath.normpath(path[lstrip_len:]), open(path, 'rb'))
+      else:
+        dirs[:] = item_set.intersection(dirs)
+    return iter(self)
 
 def generateInformation(dir, info=id, err=None):
   xml = StringIO()
@@ -100,16 +188,16 @@ def generateInformation(dir, info=id, err=None):
           continue
         raise
       try:
-        property_dict = readBusinessTemplate(tar)
+        property_list = BusinessTemplate.fromTar(tar)
       finally:
         tar.close()
-    elif os.path.isfile(os.path.join(path, bt_title_path)):
+    elif os.path.isfile(os.path.join(path, 'bt', 'title')):
       info('Reading Directory %s... ' % name)
-      property_dict = readBusinessTemplateDirectory(path)
+      property_list = BusinessTemplate.fromDir(path)
     else:
       continue
     xml.write('  <template id="%s">\n' % name)
-    for k, v in sorted(property_dict.iteritems()):
+    for k, v in property_list:
       for v in (v,) if type(v) is str else v:
         xml.write('    <%s>%s</%s>\n' % (k, cgi.escape(v), k))
     xml.write('  </template>\n')
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view.xml
index 1d4b69b39414cbd83a796769fa0cf30a9244e7d1..83f050f8fa7b0b01c33a4d6d5f388dc8b5e84f26 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view.xml
@@ -108,7 +108,7 @@
                         <string>my_id</string>
                         <string>my_title</string>
                         <string>my_version</string>
-                        <string>my_revision</string>
+                        <string>my_short_revision</string>
                         <string>my_translated_building_state_title</string>
                         <string>my_translated_installation_state_title</string>
                         <string>my_description</string>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view/my_revision.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view/my_revision.xml
deleted file mode 100644
index 3d15e1286e071575d45bfb850c11f8842e4a27e8..0000000000000000000000000000000000000000
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view/my_revision.xml
+++ /dev/null
@@ -1,260 +0,0 @@
-<?xml version="1.0"?>
-<ZopeData>
-  <record id="1" aka="AAAAAAAAAAE=">
-    <pickle>
-      <global name="StringField" module="Products.Formulator.StandardFields"/>
-    </pickle>
-    <pickle>
-      <dictionary>
-        <item>
-            <key> <string>id</string> </key>
-            <value> <string>my_revision</string> </value>
-        </item>
-        <item>
-            <key> <string>message_values</string> </key>
-            <value>
-              <dictionary>
-                <item>
-                    <key> <string>external_validator_failed</string> </key>
-                    <value> <string>The input failed the external validator.</string> </value>
-                </item>
-                <item>
-                    <key> <string>required_not_found</string> </key>
-                    <value> <string>Input is required but no input given.</string> </value>
-                </item>
-                <item>
-                    <key> <string>too_long</string> </key>
-                    <value> <string>Too much input was given.</string> </value>
-                </item>
-              </dictionary>
-            </value>
-        </item>
-        <item>
-            <key> <string>overrides</string> </key>
-            <value>
-              <dictionary>
-                <item>
-                    <key> <string>alternate_name</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>css_class</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>default</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>description</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>display_maxwidth</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>display_width</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>editable</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>enabled</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>external_validator</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>extra</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>hidden</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>max_length</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>required</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>title</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>truncate</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>unicode</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>whitespace_preserve</string> </key>
-                    <value> <string></string> </value>
-                </item>
-              </dictionary>
-            </value>
-        </item>
-        <item>
-            <key> <string>tales</string> </key>
-            <value>
-              <dictionary>
-                <item>
-                    <key> <string>alternate_name</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>css_class</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>default</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>description</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>display_maxwidth</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>display_width</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>editable</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>enabled</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>external_validator</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>extra</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>hidden</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>max_length</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>required</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>title</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>truncate</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>unicode</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>whitespace_preserve</string> </key>
-                    <value> <string></string> </value>
-                </item>
-              </dictionary>
-            </value>
-        </item>
-        <item>
-            <key> <string>values</string> </key>
-            <value>
-              <dictionary>
-                <item>
-                    <key> <string>alternate_name</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>css_class</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>default</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>description</string> </key>
-                    <value> <string>the number of revision used by the business template. This number increases each time we commit a modification</string> </value>
-                </item>
-                <item>
-                    <key> <string>display_maxwidth</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>display_width</string> </key>
-                    <value> <int>20</int> </value>
-                </item>
-                <item>
-                    <key> <string>editable</string> </key>
-                    <value> <int>0</int> </value>
-                </item>
-                <item>
-                    <key> <string>enabled</string> </key>
-                    <value> <int>1</int> </value>
-                </item>
-                <item>
-                    <key> <string>external_validator</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>extra</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>hidden</string> </key>
-                    <value> <int>0</int> </value>
-                </item>
-                <item>
-                    <key> <string>max_length</string> </key>
-                    <value> <string></string> </value>
-                </item>
-                <item>
-                    <key> <string>required</string> </key>
-                    <value> <int>0</int> </value>
-                </item>
-                <item>
-                    <key> <string>title</string> </key>
-                    <value> <string>Revision Number</string> </value>
-                </item>
-                <item>
-                    <key> <string>truncate</string> </key>
-                    <value> <int>0</int> </value>
-                </item>
-                <item>
-                    <key> <string>unicode</string> </key>
-                    <value> <int>0</int> </value>
-                </item>
-                <item>
-                    <key> <string>whitespace_preserve</string> </key>
-                    <value> <int>0</int> </value>
-                </item>
-              </dictionary>
-            </value>
-        </item>
-      </dictionary>
-    </pickle>
-  </record>
-</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view/my_short_revision.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view/my_short_revision.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c39cd9c9e7c6ff1db9749119968c6739cd30ca14
--- /dev/null
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BusinessTemplate_view/my_short_revision.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>delegated_list</string> </key>
+            <value>
+              <list>
+                <string>description</string>
+                <string>editable</string>
+                <string>title</string>
+              </list>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>my_short_revision</string> </value>
+        </item>
+        <item>
+            <key> <string>message_values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>external_validator_failed</string> </key>
+                    <value> <string>The input failed the external validator.</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>overrides</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>tales</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string></string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string></string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+        <item>
+            <key> <string>values</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>description</string> </key>
+                    <value> <string>A shortened hash of the contents of the Business Template. The hash is computed at download, build and export.</string> </value>
+                </item>
+                <item>
+                    <key> <string>editable</string> </key>
+                    <value> <int>0</int> </value>
+                </item>
+                <item>
+                    <key> <string>field_id</string> </key>
+                    <value> <string>my_string_field</string> </value>
+                </item>
+                <item>
+                    <key> <string>form_id</string> </key>
+                    <value> <string>Base_viewFieldLibrary</string> </value>
+                </item>
+                <item>
+                    <key> <string>target</string> </key>
+                    <value> <string>Click to edit the target</string> </value>
+                </item>
+                <item>
+                    <key> <string>title</string> </key>
+                    <value> <string>Revision Number</string> </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewBusinessTemplateList/listbox.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewBusinessTemplateList/listbox.xml
index e89be774746715414206e7efaf8420781b767c26..ed173bff20b48dce2b13b3a47d9e204cbfd68f3a 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewBusinessTemplateList/listbox.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewBusinessTemplateList/listbox.xml
@@ -349,7 +349,7 @@
                           <string>Version</string>
                         </tuple>
                         <tuple>
-                          <string>revision</string>
+                          <string>short_revision</string>
                           <string>Revision</string>
                         </tuple>
                         <tuple>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewInstallRepositoryBusinessTemplateListDialog/listbox.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewInstallRepositoryBusinessTemplateListDialog/listbox.xml
index 71cd4082ac498255bfee3454f3b24506f5bfed01..1e9e616b82051f0c5317f61e78f6a2dc0b4af921 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewInstallRepositoryBusinessTemplateListDialog/listbox.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewInstallRepositoryBusinessTemplateListDialog/listbox.xml
@@ -340,7 +340,7 @@
                           <string>Version</string>
                         </tuple>
                         <tuple>
-                          <string>revision</string>
+                          <string>short_revision</string>
                           <string>Revision</string>
                         </tuple>
                         <tuple>
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewUpgradeRepositoryBusinessTemplateListDialog/listbox.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewUpgradeRepositoryBusinessTemplateListDialog/listbox.xml
index 6e0a3ece833a226fad2a8ada1efb92742faeadff..d8f1a26e2a7594e5428507f36f8d337dbd563260 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewUpgradeRepositoryBusinessTemplateListDialog/listbox.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/TemplateTool_viewUpgradeRepositoryBusinessTemplateListDialog/listbox.xml
@@ -343,14 +343,14 @@
                           <string>version</string>
                           <string>Version</string>
                         </tuple>
-                        <tuple>
-                          <string>revision</string>
-                          <string>Revision</string>
-                        </tuple>
                         <tuple>
                           <string>installed_version</string>
                           <string>Installed Version</string>
                         </tuple>
+                        <tuple>
+                          <string>short_revision</string>
+                          <string>Revision</string>
+                        </tuple>
                         <tuple>
                           <string>installed_revision</string>
                           <string>Installed Revision</string>
@@ -367,10 +367,6 @@
                           <string>license</string>
                           <string>License</string>
                         </tuple>
-                        <tuple>
-                          <string>version_state_title</string>
-                          <string>State</string>
-                        </tuple>
                       </list>
                     </value>
                 </item>
diff --git a/product/ERP5/genbt5list.py b/product/ERP5/genbt5list.py
new file mode 120000
index 0000000000000000000000000000000000000000..938efd27c7148d704f79269d15774049b183c302
--- /dev/null
+++ b/product/ERP5/genbt5list.py
@@ -0,0 +1 @@
+bin/genbt5list
\ No newline at end of file
diff --git a/product/ERP5/tests/testBusinessTemplate.py b/product/ERP5/tests/testBusinessTemplate.py
index be7e6234fa5f99297c92f65958e6a4b0f652e4c2..a36589aed9e834f1d4958ca9a9633124ce664312 100644
--- a/product/ERP5/tests/testBusinessTemplate.py
+++ b/product/ERP5/tests/testBusinessTemplate.py
@@ -2824,24 +2824,6 @@ class BusinessTemplateMixin(TestDeveloperMixin, ERP5TypeTestCase, LogInterceptor
     self.failUnless(base_category_obj is not None)
     self.assertEquals(len(base_category_obj.objectIds()), 0)
 
-  def stepCheckInitialRevision(self, sequence=None, **kw):
-    """ Check if revision of a new bt is an empty string
-    """
-    bt = sequence.get('current_bt')
-    self.assertEqual(bt.getRevision(), '')
-
-  def stepCheckFirstRevision(self, sequence=None, **kw):
-    """ Check if revision of the bt is 1
-    """
-    bt = sequence.get('current_bt')
-    self.assertEqual(bt.getRevision(), '1')
-
-  def stepCheckSecondRevision(self, sequence=None, **kw):
-    """ Check if revision of the bt is 2
-    """
-    bt = sequence.get('current_bt')
-    self.assertEqual(bt.getRevision(), '2')
-
   def stepCheckNoMissingDependencies(self, sequence=None, **kw):
     """ Check if bt has no missing dependency
     """
@@ -5126,26 +5108,6 @@ class TestBusinessTemplate(BusinessTemplateMixin):
     sequence_list.addSequenceString(sequence_string)
     sequence_list.play(self)
 
-  # test of portal types
-  def test_22_RevisionNumberIsIncremented(self):
-    """Test is revision number is incremented with the bt is built"""
-    sequence_list = SequenceList()
-    sequence_string = '\
-                       CreatePortalType \
-                       CreateNewBusinessTemplate \
-                       UseExportBusinessTemplate \
-                       CheckInitialRevision \
-                       BuildBusinessTemplate \
-                       CheckBuiltBuildingState \
-                       stepCheckFirstRevision \
-                       BuildBusinessTemplate \
-                       stepCheckSecondRevision \
-                       RemoveBusinessTemplate \
-                       RemovePortalType \
-                       '
-    sequence_list.addSequenceString(sequence_string)
-    sequence_list.play(self)
-
   def test_23_CheckNoDependencies(self):
     """Test if a new Business Template has no dependencies"""
     sequence_list = SequenceList()
diff --git a/product/ERP5/tests/testTemplateTool.py b/product/ERP5/tests/testTemplateTool.py
index cd0119895292d874ef0c24916a59e3096c8afbd9..d9d84fb4b98afd7a5f49e787d30b34544d156357 100644
--- a/product/ERP5/tests/testTemplateTool.py
+++ b/product/ERP5/tests/testTemplateTool.py
@@ -31,7 +31,7 @@ import os
 import shutil
 import unittest
 import random
-import transaction
+import tempfile
 from App.config import getConfiguration
 from Products.ERP5VCS.WorkingCopy import getVcsTool
 
@@ -99,32 +99,23 @@ class TestTemplateTool(ERP5TypeTestCase):
   def testUpdateBT5FromRepository(self, quiet=quiet, run=run_all_test):
     """ Test the list of bt5 returned for upgrade """
     # edit bt5 revision so that it will be marked as updatable
-    bt_list = self.templates_tool.searchFolder(title='erp5_base')
-    self.assertEquals(len(bt_list), 1)
-    erp5_base = bt_list[0].getObject()
-    try:
-      erp5_base.edit(revision=0)
-
-      updatable_bt_list = \
-        self.templates_tool.getRepositoryBusinessTemplateList(update_only=True)
-      self.assertEqual(
-           [i.title for i in updatable_bt_list if i.title == "erp5_base"],
-           ["erp5_base"])
-      erp5_base.replace()
-      updatable_bt_list = \
-        self.templates_tool.getRepositoryBusinessTemplateList(update_only=True)
-      self.assertEqual(
-           [i.title for i in updatable_bt_list if i.title == "erp5_base"],
-           [])
-    finally:
-      erp5_base.edit(revision=int(erp5_base.getRevision()) + 10)
+    erp5_base = self.templates_tool.getInstalledBusinessTemplate('erp5_base',
+                                                                 strict=True)
+    erp5_base._setRevision('')
+
+    self.assertTrue("erp5_base" in (bt.getTitle() for bt in
+      self.templates_tool.getRepositoryBusinessTemplateList(update_only=True)))
+    erp5_base.replace()
+    self.assertFalse("erp5_base" in (bt.getTitle() for bt in
+      self.templates_tool.getRepositoryBusinessTemplateList(update_only=True)))
+    self.abort()
 
   def test_download_http(self):
     test_web = self.portal.portal_templates.download(
         'http://www.erp5.org/dists/snapshot/test_bt5/test_web.bt5')
     self.assertEquals(test_web.getPortalType(), 'Business Template')
     self.assertEquals(test_web.getTitle(), 'test_web')
-    self.assertTrue(test_web.getRevision())
+    self.assertEqual(len(test_web.getRevision()), 28)
 
   def _svn_setup_ssl(self):
     """
@@ -148,20 +139,20 @@ class TestTemplateTool(ERP5TypeTestCase):
     test_web = self.portal.portal_templates.download(bt5_url)
     self.assertEquals(test_web.getPortalType(), 'Business Template')
     self.assertEquals(test_web.getTitle(), 'test_web')
-    self.assertTrue(test_web.getRevision())
+    self.assertEqual(len(test_web.getRevision()), 28)
 
   def test_updateBusinessTemplateFromUrl_simple(self):
     """
      Test updateBusinessTemplateFromUrl method
 
-     By default if a new business template has revision >= previous one
+     By default if a new business template has revision != previous one
      the new bt5 is not installed, only imported.
     """
     self._svn_setup_ssl()
     template_tool = self.portal.portal_templates
     old_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
-    # change revision to an old revision
-    old_bt.setRevision(0.0001)
+    # fake different revision
+    old_bt.setRevision('')
     url = 'https://svn.erp5.org/repos/public/erp5/trunk/bt5/erp5_csv_style'
     template_tool.updateBusinessTemplateFromUrl(url)
     new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
@@ -170,7 +161,7 @@ class TestTemplateTool(ERP5TypeTestCase):
 
     # Test Another time with definning an ID
     old_bt = new_bt
-    old_bt.setRevision(0.0002)
+    old_bt.setRevision('')
     template_tool.updateBusinessTemplateFromUrl(url, id="new_erp5_csv_style")
     new_bt = template_tool.getInstalledBusinessTemplate('erp5_csv_style')
     self.assertNotEquals(old_bt, new_bt)
@@ -184,8 +175,7 @@ class TestTemplateTool(ERP5TypeTestCase):
     self.assertEquals(old_bt, new_bt)
     self.assertEquals('erp5_csv_style', new_bt.getTitle())
     self.assertEquals('new_erp5_csv_style', new_bt.getId())
-    not_installed_bt5 = getattr(template_tool, "not_installed_bt5", None)
-    self.assertNotEquals(not_installed_bt5, None)
+    not_installed_bt5 = template_tool['not_installed_bt5']
     self.assertEquals('erp5_csv_style', not_installed_bt5.getTitle())
     self.assertEquals(not_installed_bt5.getInstallationState(),
                       "not_installed")
@@ -204,10 +194,8 @@ class TestTemplateTool(ERP5TypeTestCase):
                                    keep_original_list=keep_original_list)
     bt = template_tool.getInstalledBusinessTemplate('test_core')
     self.assertNotEquals(None, bt)
-    erp5_test = getattr(self.portal.portal_skins, 'erp5_test', None)
-    self.assertNotEquals(None, erp5_test)
-    test_file = getattr(erp5_test, 'test_file', None)
-    self.assertEquals(None, test_file)
+    erp5_test = self.portal.portal_skins['erp5_test']
+    self.assertFalse(erp5_test.hasObject('test_file'))
 
   def test_updateBusinessTemplateFromUrl_after_before_script(self):
     """
@@ -248,48 +236,6 @@ class TestTemplateTool(ERP5TypeTestCase):
     self.assertEquals(bt.getChangeLog(), 'MODIFIED')
     self.assertEquals(portal.getTitle(), 'MODIFIED')
 
-  def test_updateBusinessTemplateFromUrl_stringCastingBug(self):
-    pt = self.getTemplateTool()
-    template = pt.newContent(portal_type='Business Template')
-    self.failUnless(template.getBuildingState() == 'draft')
-    self.failUnless(template.getInstallationState() == 'not_installed')
-    title = 'install_casting_to_int_bug_check'
-    template.edit(title=title,
-                  version='1.0',
-                  description='bt for unit_test')
-    self.commit()
-
-    template.build()
-    self.commit()
-
-    cfg = getConfiguration()
-    template_path = os.path.join(cfg.instancehome, 'tests', '%s' % (title,))
-    # remove previous version of bt it exists
-    if os.path.exists(template_path):
-      shutil.rmtree(template_path)
-    template.export(path=template_path, local=1)
-    self.failUnless(os.path.exists(template_path))
-
-    # setup version '9'
-    first_revision = '9'
-    open(os.path.join(template_path, 'bt', 'revision'), 'w').write(first_revision)
-    pt.updateBusinessTemplateFromUrl(template_path)
-    new_bt = pt.getInstalledBusinessTemplate(title)
-
-    self.assertEqual(new_bt.getRevision(), first_revision)
-
-    # setup revision '11', becasue: '11' < '9' (string comp), but 11 > 9 (int comp)
-    second_revision = '11'
-    self.assertTrue(second_revision < first_revision)
-    self.assertTrue(int(second_revision) > int(first_revision))
-
-    open(os.path.join(template_path, 'bt', 'revision'), 'w').write(second_revision)
-    pt.updateBusinessTemplateFromUrl(template_path)
-    newer_bt = pt.getInstalledBusinessTemplate(title)
-
-    self.assertNotEqual(new_bt, newer_bt)
-    self.assertEqual(newer_bt.getRevision(), second_revision)
-
   def test_CompareVersions(self):
     """Tests compare version on template tool. """
     compareVersions = self.getPortal().portal_templates.compareVersions
@@ -320,12 +266,45 @@ class TestTemplateTool(ERP5TypeTestCase):
     self.assertEquals(None, self.getPortal()\
         .portal_templates.getInstalledBusinessTemplate('erp5_toto'))
 
-  def test_getInstalledBusinessTemplateRevision(self):
-    self.assertTrue(300 < self.getPortal()\
-        .portal_templates.getInstalledBusinessTemplateRevision('erp5_core'))
-
-    self.assertEquals(None, self.getPortal()\
-        .portal_templates.getInstalledBusinessTemplateRevision('erp5_toto'))
+  def test_revision(self):
+    template_tool = self.portal.portal_templates
+    getInstalledRevision = template_tool.getInstalledBusinessTemplateRevision
+    self.assertEqual(None, getInstalledRevision('erp5_toto'))
+    available_bt, = template_tool.getRepositoryBusinessTemplateList(
+      template_list=('test_core',))
+    revision = available_bt.getRevision()
+    self.assertEqual('PN8VPt52MbdHtxfjKvL+MBsNbzM=', revision)
+    installed_bt = template_tool.download("%s/%s" % (available_bt.repository,
+                                                     available_bt.filename))
+    self.assertEqual(revision, installed_bt.getRevision())
+    installed_bt.install()
+    self.assertEqual(revision, getInstalledRevision('test_core'))
+    bt = installed_bt.Base_createCloneDocument(batch_mode=1)
+    bt.build(update_revision=False)
+    root = tempfile.mkdtemp()
+    try:
+      bt.export(root, local=1)
+      with open(os.path.join(root, 'bt', 'title')) as f:
+        self.assertTrue('test_core', f.read())
+      # We don't export revision anymore.
+      self.assertFalse(os.path.exists(os.path.join(root, 'bt', 'revision')))
+      # Computed at download ...
+      self.assertEqual(revision, template_tool.download(root).getRevision())
+    finally:
+      shutil.rmtree(root)
+    bt._setVersion("2.0")
+    # ... at building by default ...
+    bt.build()
+    revision = bt.getRevision()
+    self.assertEqual('tPNr/gGXaa0fYCsFUWe8nqzSNLc=', revision)
+    self.portal.portal_skins.erp5_test.manage_renameObject('test_file',
+                                                           'test_file2')
+    bt.build(update_revision=False)
+    self.assertEqual(revision, bt.getRevision())
+    # ... and at export.
+    bt.export(str(random.random()))
+    self.assertEqual('Nup/xsO1xpsmdJ5GTdknuVJyOr8=', bt.getRevision())
+    self.abort()
 
   def test_getInstalledBusinessTemplateList(self):
     templates_tool = self.getPortal().portal_templates
@@ -479,9 +458,9 @@ class TestTemplateTool(ERP5TypeTestCase):
     bt_old = self.templates_tool.getInstalledBusinessTemplate(bt5_name, strict=True)
     self.assertEquals(bt.getId(), bt_old.getId())
 
-    # Repeat operation, new bt5 should be inslalled due only_newer = False
+    # Repeat operation, new bt5 should be inslalled due only_different = False
     operation_log = self.templates_tool.installBusinessTemplateListFromRepository(
-          [bt5_name], only_newer=False)
+          [bt5_name], only_different=False)
 
     self.assertTrue("Installed %s with" % bt5_name in operation_log[-1])
     bt_new = self.templates_tool.getInstalledBusinessTemplate(bt5_name,
@@ -498,7 +477,7 @@ class TestTemplateTool(ERP5TypeTestCase):
       bt = template_tool.getInstalledBusinessTemplate(bt5_name)
       self.assertEquals(bt, None)
       operation_log = template_tool.installBusinessTemplateListFromRepository([bt5_name],
-                            only_newer=False, update_catalog=0)
+                            only_different=False, update_catalog=0)
 
       self.assertTrue("Installed %s with" % bt5_name in operation_log[0])
       bt = template_tool.getInstalledBusinessTemplate(bt5_name)
@@ -514,7 +493,7 @@ class TestTemplateTool(ERP5TypeTestCase):
 
       bt5_name = 'erp5_odt_style'
       operation_log = template_tool.installBusinessTemplateListFromRepository([bt5_name],
-                            only_newer=False, update_catalog=1)
+                            only_different=False, update_catalog=1)
       self.assertTrue("Installed %s with" % bt5_name in operation_log[-1])
       bt = template_tool.getInstalledBusinessTemplate(bt5_name)
       self.assertEquals(bt.getTitle(), bt5_name)
@@ -524,7 +503,7 @@ class TestTemplateTool(ERP5TypeTestCase):
 
       # Install again should not force catalog to be updated
       operation_log = template_tool.installBusinessTemplateListFromRepository(
-                [bt5_name], only_newer=False)
+                [bt5_name], only_different=False)
       self.assertTrue("Installed %s with" % bt5_name in operation_log[-1])
       bt = template_tool.getInstalledBusinessTemplate(bt5_name)
       self.assertNotEquals(bt, None)
@@ -609,7 +588,7 @@ class TestTemplateTool(ERP5TypeTestCase):
     self.assertNotEquals(bt, None)
     bt = template_tool.getInstalledBusinessTemplate("erp5_workflow")
     self.assertNotEquals(bt, None)
-    transaction.abort()
+    self.abort()
 
     # Same as above but also check that dependencies are properly resolved if
     # one of the dependency is explicitly added to the list of bt5 to be
@@ -625,22 +604,23 @@ class TestTemplateTool(ERP5TypeTestCase):
     self.assertNotEquals(bt, None)
     bt = template_tool.getInstalledBusinessTemplate("erp5_workflow")
     self.assertNotEquals(bt, None)
-    transaction.abort()
+    self.abort()
 
   def test_installBusinessTemplateListFromRepository_ignore_when_installed(self):
     """Check that install one business template, this method does not download
     many business templates that are already installed
     """
     template_tool = self.portal.portal_templates
-    # Delete not installed bt5 to check easily if more not installed was
-    # created
-    for bt5 in template_tool.getBuiltBusinessTemplateList():
-      bt5.delete()
-    bt5_name_list = ['erp5_calendar']
-    template_tool.installBusinessTemplateListFromRepository(bt5_name_list,
+    before = dict((bt.getTitle(), bt.getId())
+      for bt in template_tool.getInstalledBusinessTemplateList())
+    bt_title = 'erp5_calendar'
+    template_tool.installBusinessTemplateListFromRepository([bt_title],
         install_dependency=True)
     self.tic()
-    self.assertEquals(template_tool.getBuiltBusinessTemplateList(), [])
+    after = dict((bt.getTitle(), bt.getId())
+      for bt in template_tool.getInstalledBusinessTemplateList())
+    del after[bt_title]
+    self.assertEqual(before, after)
 
   def test_sortBusinessTemplateList(self):
     """Check sorting of a list of business template by their dependencies
diff --git a/product/ERP5Type/tests/ERP5TypeTestCase.py b/product/ERP5Type/tests/ERP5TypeTestCase.py
index f322751c55ccdc8410bc57dede959f14131e65bc..d4a0fb2f40ee1eb26907ed5d18641ed9b29b406b 100644
--- a/product/ERP5Type/tests/ERP5TypeTestCase.py
+++ b/product/ERP5Type/tests/ERP5TypeTestCase.py
@@ -461,43 +461,15 @@ class ERP5TypeTestCaseMixin(ProcessingNodeTestCase, PortalTestCase):
            DeprecationWarning)
       return self.createUserAssignment(user, assignment_kw)
 
-    def setupAutomaticBusinessTemplateRepository(self, accept_public=True,
-                              searchable_business_template_list=None):
-     # Try to setup some valid Repository List by reusing ERP5TypeTestCase API.
-     # if accept_public we can accept public repository can be set, otherwise
-     # we let failure happens.
-     if searchable_business_template_list is None:
-       searchable_business_template_list = ["erp5_base"]
-
-     # Assume that the public official repository is a valid repository
-     public_bt5_repository_list = ['http://www.erp5.org/dists/snapshot/bt5/']
-
-     template_list = []
-     for bt_id in searchable_business_template_list:
-       bt_template_list = self._getBTPathAndIdList([bt_id])
-       if len(bt_template_list):
-         template_list.append(bt_template_list[0])
-     if len(template_list) > 0:
-       bt5_repository_path_list = ["/".join(x[0].split("/")[:-1])
-                                   for x in template_list]
-       if accept_public:
-         try:
-           self.portal.portal_templates.updateRepositoryBusinessTemplateList(
-                  bt5_repository_path_list, None)
-         except (RuntimeError, IOError), e:
-           # If bt5 repository is not a repository use public one.
-           self.portal.portal_templates.updateRepositoryBusinessTemplateList(
-                                   public_bt5_repository_list)
-       else:
-         self.portal.portal_templates.updateRepositoryBusinessTemplateList(
-                  bt5_repository_path_list, None)
-     elif accept_public:
-       self.portal.portal_templates.updateRepositoryBusinessTemplateList(
-                                     public_bt5_repository_list)
-     else:
-       raise ValueError("ERP5 was unable to determinate a valid local " + \
-                        "repository, please check your environment or " + \
-                        "use accept_public as True")
+    def setupAutomaticBusinessTemplateRepository(self,
+                              searchable_business_template_list=("erp5_base",)):
+      template_tool = self.portal.portal_templates
+      bt_set = set(searchable_business_template_list).difference(x['title']
+        for x in template_tool.repository_dict.itervalues() for x in x)
+      if bt_set:
+        template_tool.updateRepositoryBusinessTemplateList(set(
+          os.path.dirname(x[0]) for x in self._getBTPathAndIdList(bt_set)),
+          genbt5list=1)
 
     def failIfDifferentSet(self, a, b, msg=""):
       if not msg:
diff --git a/product/ERP5VCS/WorkingCopy.py b/product/ERP5VCS/WorkingCopy.py
index a49b7d90530a84c15d504a946c0d132c3fa8c579..0e73d38be658742e96f97273ec90edee2e8f765f 100644
--- a/product/ERP5VCS/WorkingCopy.py
+++ b/product/ERP5VCS/WorkingCopy.py
@@ -187,7 +187,7 @@ class WorkingCopy(Implicit):
     """
     if business_template.getBuildingState() == 'draft':
       business_template.edit()
-    business_template.build()
+    business_template.build(update_revision=False)
     self._export(business_template)
 
   def _export(self, business_template):
@@ -200,16 +200,6 @@ class WorkingCopy(Implicit):
   def update(self, keep=False):
     raise NotAWorkingCopyError
 
-  def newRevision(self):
-    path = os.path.join('bt', 'revision')
-    try:
-      revision = int(self.showOld(path)) + 1
-    except NotVersionedError:
-      return 1
-    with open(os.path.join(self.working_copy, path), 'w') as file:
-      file.write(str(revision))
-    return revision
-
   def hasDiff(self, path):
     try:
       hasDiff = aq_base(self).__hasDiff
@@ -329,7 +319,7 @@ class WorkingCopy(Implicit):
                                         title='tmp_bt_revert',
                                         template_path_list=path_added_list)
       tmp_bt.edit()
-      tmp_bt.build()
+      tmp_bt.build(update_revision=False)
       # Install then uninstall it to remove objects from ZODB
       tmp_bt.install()
       tmp_bt.uninstall()