[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Fwd: svn1.5 seems to fail simple merge-tracking scenario

From: Trent Nelson <svn-users-list_at_trentnelson.com>
Date: Fri, 20 Feb 2009 21:45:48 +0000

On Fri, Feb 20, 2009 at 04:22:18PM -0500, Bob Archer wrote:
> > Ah hah! That is the best thing I've read all month. I can simply
> > do that in a post-commit hook after detecting that a branch has
> > just been re-integrated. Sweeeet.
> I'm not sure how you are going to detect that. As far as the server
> knows this is a commit no different than any other.

% find ~e/data/python/lib/shell/svn -type f -iname "*.py" | xargs cat | wc -l

    With a 6000+ line Python framework, that's how ;-)

> If it were this easy, wouldn't the svn devs be able to do this. But,
> then again, they could create a merge property on the target of the
> --reintegrate to identify it as such and then when that property is
> committed it could update the merge properties on the branch the
> property references.
> Hmm... seems too easy... what am I missing?

    It was far from easy. It's sucked the life out of me for the past
    three weeks or so. I had to build another semantic layer on top of
    Subversion, such that, for a given repository, you would define the
    paths that correspond to trunk, tags, and branches, such that you
    can analyse a commit and figure out exactly what a user is doing.

    Are they trying to copy a tag? Are they trying to create a branch
    from a tag? Have they correctly rooted their commit (i.e. they're
    not committing files in branch/foo as well as trunk)? Are they
    trying to re-integrate more than one branch at a time? Are they
    trying to revision merge a branch back to trunk when they should
    be re-integrating? Are they reverse merging, and if so, are they
    reverse merging within the agreed parameters (i.e. only allow a
    commit to be a single reverse merge of a previously re-integrated
    branch; no multiple reverse merges or combined forward+reverse
    merges are allowed). Are they trying to modify a tag in any way,
    shape or form?

    Subversion lets you do all of this. In an enterprise context, where
    you can't control the calibre of developers, you really need to lock
    this down though -- mainly to protect developers that don't know the
    ins and outs of Subversion more than anything else.

    Now that I've got this semantic layer sitting on top of each repo, I
    can write hooks like this:

class MergeControl(RepositoryHook):
    id = 'validate-merge'
    def pre_commit(self, txn):
        pathmatcher = self.repo.get_path_matcher()
        changeset = self.repo.changeset(txn)
        analysis = changeset.analysis
        root_path = changeset.root_dir
        root_dir, root_type, root_name = pathmatcher.get_root_details(root_path)
        if analysis.is_merge:
            if not analysis.is_single_merge_source:
                self.terminate('detected multiple merge sources')
            if analysis.is_foreign_merge_source:
                self.terminate('detected attempt to merge foreign branch')
            if root_type == 'trunk':
                if not analysis.is_reintegration:
                    self.terminate('feature branches must be merged back to '
                                   'trunk via re-integration; cherry-picking '
                                   'revisions is not permitted')
            elif root_type == 'branch':
                if analysis.merge_root_type != 'trunk':
                    self.terminate('detected attempt to synchronise feature '
                                  'branch with something other than trunk')

    def post_commit(self, rev):
        pathmatcher = self.repo.get_path_matcher()
        changset = self.repo.changeset(rev)
        analysis = changeset.analysis
        root_path = changeset.root_dir
        root_dir, root_type, root_name = pathmatcher.get_root_details(root_path)
        if root_type == 'trunk':
            if analysis.is_reintegration:
                # Record the merge back on the branch such that future
                # re-integrations work.
                self.repo.merge(analysis.merge_root_dir, root_dir, rev,

class TagControl(RepositoryHook):
    id = 'tag-control'
    def pre_commit(self, txn):
        pathmatcher = self.repo.get_path_matcher()
        changeset = self.repo.changeset(txn)
        analysis = changeset.analysis
        root_path = changeset.root_dir
        root_dir, root_type, root_name = pathmatcher.get_root_details(root_path)
        if root_type == 'tag':
            if not analysis.is_copy:
                self.terminate('tags cannot be modified after creation')
            if not analysis.is_clean:
                self.terminate('tag is not a clean copy')
            assert not analysis.is_subtree_change
            base_path = changeset.root_change.base_path
            base_root_details = pathmatcher.get_root_details(base_path)
            # Verify that a tag is being made of something legitimate.
            base_root_dir, base_root_type, base_root_name = base_root_details
            if base_root_type == 'tag':
                self.terminate('tags cannot be copied')
            elif base_root_type not in ('branch', 'trunk') or \
                self.terminate('only release branches and trunk can be tagged')
Received on 2009-02-20 22:46:44 CET

This is an archived mail posted to the Subversion Users mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.