def test_push_single_dir_one_incoming_and_two_outgoing(self):
        # Tests simple pushing from default branch to a single dir repo
        # Pushes two outgoing over one incoming svn rev
        # (used to cause an "unknown revision")
        # This can happen if someone committed to svn since our last pull (race).
        repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                              layout='single',
                                              subdir='trunk')
        self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed'})

        def file_callback(repo, memctx, path):
            return compathacks.makememfilectx(repo,
                                              memctx=memctx,
                                              path=path,
                                              data='data of %s' % path,
                                              islink=False,
                                              isexec=False,
                                              copied=False)

        for fn in ['one', 'two']:
            ctx = context.memctx(repo, (repo['tip'].node(), node.nullid),
                                 'automated test', [fn], file_callback,
                                 'an_author', '2009-10-19 18:49:30 -0500', {
                                     'branch': 'default',
                                 })
            repo.commitctx(ctx)
        hg.update(repo, repo['tip'].node())
        self.pushrevisions(expected_extra_back=1)
        self.assertTrue('trunk/one' in test_util.svnls(repo_path, ''))
        self.assertTrue('trunk/two' in test_util.svnls(repo_path, ''))
 def test_push_single_dir_one_incoming_and_two_outgoing(self):
     # Tests simple pushing from default branch to a single dir repo
     # Pushes two outgoing over one incoming svn rev
     # (used to cause an "unknown revision")
     # This can happen if someone committed to svn since our last pull (race).
     repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                           layout='single',
                                           subdir='trunk')
     self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed'})
     def file_callback(repo, memctx, path):
         return compathacks.makememfilectx(repo,
                                           path=path,
                                           data='data of %s' % path,
                                           islink=False,
                                           isexec=False,
                                           copied=False)
     for fn in ['one', 'two']:
         ctx = context.memctx(repo,
                              (repo['tip'].node(), node.nullid),
                              'automated test',
                              [fn],
                              file_callback,
                              'an_author',
                              '2009-10-19 18:49:30 -0500',
                              {'branch': 'default', })
         repo.commitctx(ctx)
     hg.update(repo, repo['tip'].node())
     self.pushrevisions(expected_extra_back=1)
     self.assertTrue('trunk/one' in test_util.svnls(repo_path, ''))
     self.assertTrue('trunk/two' in test_util.svnls(repo_path, ''))
    def test_push_single_dir_branch(self):
        # Tests local branches pushing to a single dir repo. Creates a fork at
        # tip. The default branch adds a file called default, while branch foo
        # adds a file called foo, then tries to push the foo branch and default
        # branch in that order.
        repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                              layout='single',
                                              subdir='')

        def file_callback(data):
            def cb(repo, memctx, path):
                if path == data:
                    return compathacks.makememfilectx(repo,
                                                      memctx=memctx,
                                                      path=path,
                                                      data=data,
                                                      islink=False,
                                                      isexec=False,
                                                      copied=False)
                raise IOError(errno.EINVAL, 'Invalid operation: ' + path)

            return cb

        def commit_to_branch(name, parent):
            repo.commitctx(
                context.memctx(repo, (parent, node.nullid),
                               'automated test (%s)' % name, [name],
                               file_callback(name), 'an_author',
                               '2009-10-19 18:49:30 -0500', {
                                   'branch': name,
                               }))

        parent = repo['tip'].node()
        commit_to_branch('default', parent)
        commit_to_branch('foo', parent)
        hg.update(repo, revsymbol(repo, 'foo').node())
        self.pushrevisions()
        repo = self.repo  # repo is outdated after the rebase happens, refresh
        self.assertTrue('foo' in test_util.svnls(repo_path, ''))
        self.assertEqual(set(repo.branchmap()), set(['default']))
        # Have to cross to another branch head, so hg.update doesn't work
        commands.update(self.ui(),
                        self.repo,
                        node.hex(self.repo.branchheads('default')[1]),
                        clean=True)
        self.pushrevisions()
        self.assertTrue('default' in test_util.svnls(repo_path, ''))
        self.assertEquals(len(self.repo.branchheads('default')), 1)
    def test_push_single_dir_renamed_branch(self):
        # Tests pulling and pushing with a renamed branch
        # Based on test_push_single_dir
        repo_path = self.load_svndump('branch_from_tag.svndump')
        cmd = ['clone', '--layout=single', '--branch=flaf']
        if self.stupid:
            cmd.append('--stupid')
        cmd += [test_util.fileurl(repo_path), self.wc_path]
        test_util.dispatch(cmd)

        def file_callback(repo, memctx, path):
            if path == 'adding_file':
                return compathacks.makememfilectx(repo,
                                                  path=path,
                                                  data='foo',
                                                  islink=False,
                                                  isexec=False,
                                                  copied=False)
            raise IOError(errno.EINVAL, 'Invalid operation: ' + path)
        ctx = context.memctx(self.repo,
                             (self.repo['tip'].node(), node.nullid),
                             'automated test',
                             ['adding_file'],
                             file_callback,
                             'an_author',
                             '2009-10-19 18:49:30 -0500',
                             {'branch': 'default', })
        self.repo.commitctx(ctx)
        hg.update(self.repo, self.repo['tip'].node())
        self.pushrevisions()
        self.assertTrue('adding_file' in test_util.svnls(repo_path, ''))

        self.assertEquals(set(['flaf']),
                          set(self.repo[i].branch() for i in self.repo))
    def test_push_single_dir_renamed_branch(self):
        # Tests pulling and pushing with a renamed branch
        # Based on test_push_single_dir
        repo_path = self.load_svndump('branch_from_tag.svndump')
        cmd = ['clone', '--quiet', '--layout=single', '--branch=flaf']
        if self.stupid:
            cmd.append('--stupid')
        cmd += [test_util.fileurl(repo_path), self.wc_path]
        test_util.dispatch(cmd)

        def file_callback(repo, memctx, path):
            if path == 'adding_file':
                return compathacks.makememfilectx(repo,
                                                  memctx=memctx,
                                                  path=path,
                                                  data='foo',
                                                  islink=False,
                                                  isexec=False,
                                                  copied=False)
            raise IOError(errno.EINVAL, 'Invalid operation: ' + path)

        lr = self.repo
        ctx = context.memctx(lr, (lr['tip'].node(), node.nullid),
                             'automated test', ['adding_file'], file_callback,
                             'an_author', '2009-10-19 18:49:30 -0500', {
                                 'branch': 'default',
                             })
        lr.commitctx(ctx)
        hg.update(self.repo, self.repo['tip'].node())
        self.pushrevisions()
        self.assertTrue('adding_file' in test_util.svnls(repo_path, ''))

        self.assertEquals(set(['flaf']),
                          set(self.repo[i].branch() for i in self.repo))
    def test_push_single_dir_branch(self):
        # Tests local branches pushing to a single dir repo. Creates a fork at
        # tip. The default branch adds a file called default, while branch foo
        # adds a file called foo, then tries to push the foo branch and default
        # branch in that order.
        repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                              layout='single',
                                              subdir='')
        def file_callback(data):
            def cb(repo, memctx, path):
                if path == data:
                    return compathacks.makememfilectx(repo,
                                                      path=path,
                                                      data=data,
                                                      islink=False,
                                                      isexec=False,
                                                      copied=False)
                raise IOError(errno.EINVAL, 'Invalid operation: ' + path)
            return cb

        def commit_to_branch(name, parent):
            repo.commitctx(context.memctx(repo,
                                          (parent, node.nullid),
                                          'automated test (%s)' % name,
                                          [name],
                                          file_callback(name),
                                          'an_author',
                                          '2009-10-19 18:49:30 -0500',
                                          {'branch': name, }))

        parent = repo['tip'].node()
        commit_to_branch('default', parent)
        commit_to_branch('foo', parent)
        hg.update(repo, repo['foo'].node())
        self.pushrevisions()
        repo = self.repo # repo is outdated after the rebase happens, refresh
        self.assertTrue('foo' in test_util.svnls(repo_path, ''))
        self.assertEqual(compathacks.branchset(repo), set(['default']))
        # Have to cross to another branch head, so hg.update doesn't work
        commands.update(ui.ui(),
                        self.repo,
                        self.repo.branchheads('default')[1],
                        clean=True)
        self.pushrevisions()
        self.assertTrue('default' in test_util.svnls(repo_path, ''))
        self.assertEquals(len(self.repo.branchheads('default')), 1)
 def test_push_new_file_existing_dir_root_not_repo_root(self):
     repo_path = self.load_and_fetch('empty_dir_in_trunk_not_repo_root.svndump',
                                     subdir='project')[1]
     changes = [('narf/a', 'narf/a', 'ohai',),
                ]
     self.commitchanges(changes)
     self.assertEqual(test_util.svnls(repo_path, 'project/trunk'), ['a',
                                                    'narf',
                                                    ])
     self.pushrevisions()
     self.assertEqual(test_util.svnls(repo_path, 'project/trunk'), ['a',
                                                    'narf',
                                                    'narf/a'])
     changes = [('narf/a', None, None,),
                ]
     self.commitchanges(changes)
     self.pushrevisions()
     self.assertEqual(test_util.svnls(repo_path, 'project/trunk'), ['a'])
    def test_push_dirs(self):
        repo_path = self.load_and_fetch('emptyrepo.svndump')[1]

        changes = [
            # Single file in single directory
            ('d1/a', 'd1/a', 'a\n'),
            # Two files in one directory
            ('d2/a', 'd2/a', 'a\n'),
            ('d2/b', 'd2/b', 'a\n'),
            # Single file in empty directory hierarchy
            ('d31/d32/d33/d34/a', 'd31/d32/d33/d34/a', 'a\n'),
            ('d31/d32/a', 'd31/d32/a', 'a\n'),
            ]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertEqual(test_util.svnls(repo_path, 'trunk'),
                          ['d1', 'd1/a', 'd2', 'd2/a', 'd2/b', 'd31',
                           'd31/d32', 'd31/d32/a', 'd31/d32/d33',
                           'd31/d32/d33/d34', 'd31/d32/d33/d34/a'])

        # Add one revision with changed files only, no directory addition
        # or deletion.
        changes = [
            ('d1/a', 'd1/a', 'aa\n'),
            ('d2/a', 'd2/a', 'aa\n'),
            ]
        self.commitchanges(changes)
        self.pushrevisions()

        changes = [
            # Remove single file in single directory
            ('d1/a', None, None),
            # Remove one file out of two
            ('d2/a', None, None),
            # Removing this file should remove one empty parent dir too
            ('d31/d32/d33/d34/a', None, None),
            ]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertEqual(test_util.svnls(repo_path, 'trunk'),
                         ['d2', 'd2/b', 'd31', 'd31/d32', 'd31/d32/a', ])
 def test_push_new_dir_project_root_not_repo_root(self):
     repo_path = self.load_and_fetch('fetch_missing_files_subdir.svndump',
                                     subdir='foo')[1]
     changes = [('magic_new/a', 'magic_new/a', 'ohai',),
                ]
     self.commitchanges(changes)
     self.pushrevisions()
     self.assertEqual(test_util.svnls(repo_path, 'foo/trunk'), ['bar',
                                                'bar/alpha',
                                                'bar/beta',
                                                'bar/delta',
                                                'bar/gamma',
                                                'foo',
                                                'magic_new',
                                                'magic_new/a'])
    def test_push_rename_tree(self):
        repo = self.repo

        changes = [
            ('geek/alpha', 'geek/alpha', 'content',),
            ('geek/beta', 'geek/beta', 'content',),
            ('geek/delta', 'geek/delta', 'content',),
            ('geek/gamma', 'geek/gamma', 'content',),
            ('geek/later/pi', 'geek/later/pi', 'content geek/later/pi',),
            ('geek/later/rho', 'geek/later/rho', 'content geek/later/rho',),
            ('geek/other/blah', 'geek/other/blah', 'content geek/other/blah',),
            ('geek/other/another/layer', 'geek/other/another/layer', 'content deep file',),
            ]

        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])

        changes = [
            # rename (copy + remove) all of geek to greek
            ('geek/alpha', 'greek/alpha', None,),
            ('geek/beta', 'greek/beta', None,),
            ('geek/delta', 'greek/delta', None,),
            ('geek/gamma', 'greek/gamma', None,),
            ('geek/later/pi', 'greek/later/pi', None,),
            ('geek/later/rho', 'greek/later/rho', None,),
            ('geek/other/blah', 'greek/other/blah', None,),
            ('geek/other/another/layer', 'greek/other/another/layer', None,),

            ('geek/alpha', None, None,),
            ('geek/beta', None, None,),
            ('geek/delta', None, None,),
            ('geek/gamma', None, None,),
            ('geek/later/pi', None, None,),
            ('geek/later/rho', None, None,),
            ('geek/other/blah', None, None,),
            ('geek/other/another/layer', None, None,),
            ]
        self.commitchanges(changes)
        self.pushrevisions()
        assert reduce(lambda x, y: x and y,
                      ('geek' not in f for f in test_util.svnls(self.repo_path, 'trunk'))), (
            'This failure means rename of an entire tree is broken.'
            ' There is a print on the preceding line commented out '
            'that should help you.')
    def test_push_single_dir(self):
        # Tests simple pushing from default branch to a single dir repo
        repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                              layout='single',
                                              subdir='')

        def file_callback(repo, memctx, path):
            if path == 'adding_file':
                return compathacks.makememfilectx(repo,
                                                  memctx=memctx,
                                                  path=path,
                                                  data='foo',
                                                  islink=False,
                                                  isexec=False,
                                                  copied=False)
            elif path == 'adding_binary':
                return compathacks.makememfilectx(repo,
                                                  memctx=memctx,
                                                  path=path,
                                                  data='\0binary',
                                                  islink=False,
                                                  isexec=False,
                                                  copied=False)
            raise IOError(errno.EINVAL, 'Invalid operation: ' + path)

        ctx = context.memctx(repo, (repo['tip'].node(), node.nullid),
                             'automated test',
                             ['adding_file', 'adding_binary'], file_callback,
                             'an_author', '2009-10-19 18:49:30 -0500', {
                                 'branch': 'default',
                             })
        repo.commitctx(ctx)
        hg.update(repo, repo['tip'].node())
        self.pushrevisions()
        self.assertTrue('adding_file' in test_util.svnls(repo_path, ''))
        self.assertEqual(
            'application/octet-stream',
            test_util.svnpropget(repo_path, 'adding_binary', 'svn:mime-type'))
        # Now add another commit and test mime-type being reset
        changes = [('adding_binary', 'adding_binary', 'no longer binary')]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertEqual(
            '',
            test_util.svnpropget(repo_path, 'adding_binary', 'svn:mime-type'))
 def test_push_single_dir(self):
     # Tests simple pushing from default branch to a single dir repo
     repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                           layout='single',
                                           subdir='')
     def file_callback(repo, memctx, path):
         if path == 'adding_file':
             return compathacks.makememfilectx(repo,
                                               path=path,
                                               data='foo',
                                               islink=False,
                                               isexec=False,
                                               copied=False)
         elif path == 'adding_binary':
             return compathacks.makememfilectx(repo,
                                               path=path,
                                               data='\0binary',
                                               islink=False,
                                               isexec=False,
                                               copied=False)
         raise IOError(errno.EINVAL, 'Invalid operation: ' + path)
     ctx = context.memctx(repo,
                          (repo['tip'].node(), node.nullid),
                          'automated test',
                          ['adding_file', 'adding_binary'],
                          file_callback,
                          'an_author',
                          '2009-10-19 18:49:30 -0500',
                          {'branch': 'default', })
     repo.commitctx(ctx)
     hg.update(repo, repo['tip'].node())
     self.pushrevisions()
     self.assertTrue('adding_file' in test_util.svnls(repo_path, ''))
     self.assertEqual('application/octet-stream',
                      test_util.svnpropget(repo_path, 'adding_binary',
                                           'svn:mime-type'))
     # Now add another commit and test mime-type being reset
     changes = [('adding_binary', 'adding_binary', 'no longer binary')]
     self.commitchanges(changes)
     self.pushrevisions()
     self.assertEqual('', test_util.svnpropget(repo_path, 'adding_binary',
                                               'svn:mime-type'))
Exemple #13
0
 def test_push_single_dir_change_in_subdir(self):
     # Tests simple pushing from default branch to a single dir repo
     # Changes a file in a subdir (regression).
     repo, repo_path = self.load_and_fetch('branch_from_tag.svndump',
                                           layout='single',
                                           subdir='tags')
     changes = [('tag_r3/alpha', 'tag_r3/alpha', 'foo'),
                ('tag_r3/new', 'tag_r3/new', 'foo'),
                ('new_dir/new', 'new_dir/new', 'foo'),
                ]
     self.commitchanges(changes)
     self.pushrevisions()
     self.assertEqual(test_util.svnls(repo_path, 'tags'),
                      ['copied_tag',
                       'copied_tag/alpha',
                       'copied_tag/beta',
                       'new_dir',
                       'new_dir/new',
                       'tag_r3',
                       'tag_r3/alpha',
                       'tag_r3/beta',
                       'tag_r3/new'])
Exemple #14
0
    def test_push_hgsub(self):
        if subrepo is None:
            return

        repo, repo_path = self.load_and_fetch('pushexternals.svndump',
                                              externals='subrepos')
        # Add a new reference on an existing and non-existing directory
        changes = [
            ('.hgsub', '.hgsub', """\
dir/deps/project2 = [hgsubversion] dir:^/externals/project2 deps/project2
subdir1/deps/project1 = [hgsubversion] subdir1:^/externals/project1 deps/project1
subdir2/deps/project2 = [hgsubversion] subdir2:^/externals/project2 deps/project2
"""),
            ('.hgsubstate', '.hgsubstate', """\
HEAD dir/deps/project2
HEAD subdir1/deps/project1
HEAD subdir2/deps/project2
"""),
            ('subdir1/a', 'subdir1/a', 'a'),
            ('subdir2/a', 'subdir2/a', 'a'),
        ]
        self.svnco(repo_path, 'externals/project2', '2', 'dir/deps/project2')
        self.svnco(repo_path, 'externals/project1', '2',
                   'subdir1/deps/project1')
        self.svnco(repo_path, 'externals/project2', '2',
                   'subdir2/deps/project2')
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])

        # Check .hgsub and .hgsubstate were not pushed
        self.assertEqual(
            ['dir', 'subdir1', 'subdir1/a', 'subdir2', 'subdir2/a'],
            test_util.svnls(repo_path, 'trunk'))

        # Remove all references from one directory, add a new one
        # to the other (test multiline entries)
        changes = [
            ('.hgsub', '.hgsub', """\
subdir1/deps/project1 = [hgsubversion] subdir1:^/externals/project1 deps/project1
subdir1/deps/project2 = [hgsubversion] subdir1:^/externals/project2 deps/project2
"""),
            ('.hgsubstate', '.hgsubstate', """\
HEAD subdir1/deps/project1
HEAD subdir1/deps/project2
"""),
            # This removal used to trigger the parent directory removal
            ('subdir1/a', None, None),
        ]
        self.svnco(repo_path, 'externals/project1', '2',
                   'subdir1/deps/project1')
        self.svnco(repo_path, 'externals/project2', '2',
                   'subdir1/deps/project2')
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])
        # Check subdir2/a is still there even if the externals were removed
        self.assertTrue('subdir2/a' in self.repo['tip'])
        self.assertTrue('subdir1/a' not in self.repo['tip'])

        # Move the externals so they are defined on the base directory,
        # this used to cause full branch removal when deleting the .hgsub
        changes = [
            ('.hgsub', '.hgsub', """\
subdir1/deps/project1 = [hgsubversion] :^/externals/project1 subdir1/deps/project1
"""),
            ('.hgsubstate', '.hgsubstate', """\
HEAD subdir1/deps/project1
"""),
        ]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])

        # Test externals removal
        changes = [
            ('.hgsub', None, None),
            ('.hgsubstate', None, None),
        ]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])
Exemple #15
0
    def test_push_rename_tree(self):
        repo = self.repo

        changes = [
            (
                'geek/alpha',
                'geek/alpha',
                'content',
            ),
            (
                'geek/beta',
                'geek/beta',
                'content',
            ),
            (
                'geek/delta',
                'geek/delta',
                'content',
            ),
            (
                'geek/gamma',
                'geek/gamma',
                'content',
            ),
            (
                'geek/later/pi',
                'geek/later/pi',
                'content geek/later/pi',
            ),
            (
                'geek/later/rho',
                'geek/later/rho',
                'content geek/later/rho',
            ),
            (
                'geek/other/blah',
                'geek/other/blah',
                'content geek/other/blah',
            ),
            (
                'geek/other/another/layer',
                'geek/other/another/layer',
                'content deep file',
            ),
        ]

        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])

        changes = [
            # rename (copy + remove) all of geek to greek
            (
                'geek/alpha',
                'greek/alpha',
                None,
            ),
            (
                'geek/beta',
                'greek/beta',
                None,
            ),
            (
                'geek/delta',
                'greek/delta',
                None,
            ),
            (
                'geek/gamma',
                'greek/gamma',
                None,
            ),
            (
                'geek/later/pi',
                'greek/later/pi',
                None,
            ),
            (
                'geek/later/rho',
                'greek/later/rho',
                None,
            ),
            (
                'geek/other/blah',
                'greek/other/blah',
                None,
            ),
            (
                'geek/other/another/layer',
                'greek/other/another/layer',
                None,
            ),
            (
                'geek/alpha',
                None,
                None,
            ),
            (
                'geek/beta',
                None,
                None,
            ),
            (
                'geek/delta',
                None,
                None,
            ),
            (
                'geek/gamma',
                None,
                None,
            ),
            (
                'geek/later/pi',
                None,
                None,
            ),
            (
                'geek/later/rho',
                None,
                None,
            ),
            (
                'geek/other/blah',
                None,
                None,
            ),
            (
                'geek/other/another/layer',
                None,
                None,
            ),
        ]
        self.commitchanges(changes)
        self.pushrevisions()
        assert reduce(
            lambda x, y: x and y,
            ('geek' not in f
             for f in test_util.svnls(self.repo_path, 'trunk'))), (
                 'This failure means rename of an entire tree is broken.'
                 ' There is a print on the preceding line commented out '
                 'that should help you.')
Exemple #16
0
    def test_push_hgsub(self):
        if subrepo is None:
            return

        repo, repo_path = self.load_and_fetch('pushexternals.svndump',
                                              externals='subrepos')
        # Add a new reference on an existing and non-existing directory
        changes = [
            ('.hgsub', '.hgsub', """\
dir/deps/project2 = [hgsubversion] dir:^/externals/project2 deps/project2
subdir1/deps/project1 = [hgsubversion] subdir1:^/externals/project1 deps/project1
subdir2/deps/project2 = [hgsubversion] subdir2:^/externals/project2 deps/project2
"""),
            ('.hgsubstate', '.hgsubstate', """\
HEAD dir/deps/project2
HEAD subdir1/deps/project1
HEAD subdir2/deps/project2
"""),
            ('subdir1/a', 'subdir1/a', 'a'),
            ('subdir2/a', 'subdir2/a', 'a'),
            ]
        self.svnco(repo_path, 'externals/project2', '2', 'dir/deps/project2')
        self.svnco(repo_path, 'externals/project1', '2', 'subdir1/deps/project1')
        self.svnco(repo_path, 'externals/project2', '2', 'subdir2/deps/project2')
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])

        # Check .hgsub and .hgsubstate were not pushed
        self.assertEqual(['dir', 'subdir1', 'subdir1/a', 'subdir2',
                          'subdir2/a'], test_util.svnls(repo_path, 'trunk'))

        # Remove all references from one directory, add a new one
        # to the other (test multiline entries)
        changes = [
            ('.hgsub', '.hgsub', """\
subdir1/deps/project1 = [hgsubversion] subdir1:^/externals/project1 deps/project1
subdir1/deps/project2 = [hgsubversion] subdir1:^/externals/project2 deps/project2
"""),
            ('.hgsubstate', '.hgsubstate', """\
HEAD subdir1/deps/project1
HEAD subdir1/deps/project2
"""),
            # This removal used to trigger the parent directory removal
            ('subdir1/a', None, None),
            ]
        self.svnco(repo_path, 'externals/project1', '2', 'subdir1/deps/project1')
        self.svnco(repo_path, 'externals/project2', '2', 'subdir1/deps/project2')
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])
        # Check subdir2/a is still there even if the externals were removed
        self.assertTrue('subdir2/a' in self.repo['tip'])
        self.assertTrue('subdir1/a' not in self.repo['tip'])

        # Move the externals so they are defined on the base directory,
        # this used to cause full branch removal when deleting the .hgsub
        changes = [
            ('.hgsub', '.hgsub', """\
subdir1/deps/project1 = [hgsubversion] :^/externals/project1 subdir1/deps/project1
"""),
            ('.hgsubstate', '.hgsubstate', """\
HEAD subdir1/deps/project1
"""),
            ]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])

        # Test externals removal
        changes = [
            ('.hgsub', None, None),
            ('.hgsubstate', None, None),
            ]
        self.commitchanges(changes)
        self.pushrevisions()
        self.assertchanges(changes, self.repo['tip'])