def test_root_module(self, rwrepo):
		# Can query everything without problems
		rm = RootModule(self.rorepo)
		assert rm.module() is self.rorepo
		
		# try attributes
		rm.binsha
		rm.mode
		rm.path
		assert rm.name == rm.k_root_name
		assert rm.parent_commit == self.rorepo.head.commit
		rm.url
		rm.branch
		
		assert len(rm.list_items(rm.module())) == 1
		rm.config_reader()
		rm.config_writer()
		
		# deep traversal gitdb / async
		rsmsp = [sm.path for sm in rm.traverse()]
		assert len(rsmsp) >= 2			# gitdb and async [and smmap], async being a child of gitdb
		
		# cannot set the parent commit as root module's path didn't exist
		self.failUnlessRaises(ValueError, rm.set_parent_commit, 'HEAD')
		
		# TEST UPDATE
		#############
		# setup commit which remove existing, add new and modify existing submodules
		rm = RootModule(rwrepo)
		assert len(rm.children()) == 1
		
		# modify path without modifying the index entry
		# ( which is what the move method would do properly )
		#==================================================
		sm = rm.children()[0]
		pp = "path/prefix"
		fp = join_path_native(pp, sm.path)
		prep = sm.path
		assert not sm.module_exists()				# was never updated after rwrepo's clone
		
		# assure we clone from a local source 
		sm.config_writer().set_value('url', to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path)))
		
		# dry-run does nothing
		sm.update(recursive=False, dry_run=True, progress=prog)
		assert not sm.module_exists()
		
		sm.update(recursive=False)
		assert sm.module_exists()
		sm.config_writer().set_value('path', fp)	# change path to something with prefix AFTER url change
		
		# update fails as list_items in such a situations cannot work, as it cannot
		# find the entry at the changed path
		self.failUnlessRaises(InvalidGitRepositoryError, rm.update, recursive=False)
		
		# move it properly - doesn't work as it its path currently points to an indexentry
		# which doesn't exist ( move it to some path, it doesn't matter here )
		self.failUnlessRaises(InvalidGitRepositoryError, sm.move, pp)
		# reset the path(cache) to where it was, now it works
		sm.path = prep
		sm.move(fp, module=False)		# leave it at the old location
		
		assert not sm.module_exists()
		cpathchange = rwrepo.index.commit("changed sm path") # finally we can commit
		
		# update puts the module into place
		rm.update(recursive=False, progress=prog)
		sm.set_parent_commit(cpathchange)
		assert sm.module_exists()
		
		# add submodule
		#================
		nsmn = "newsubmodule"
		nsmp = "submrepo"
		async_url = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, rsmsp[0], rsmsp[1]))
		nsm = Submodule.add(rwrepo, nsmn, nsmp, url=async_url)
		csmadded = rwrepo.index.commit("Added submodule").hexsha	# make sure we don't keep the repo reference
		nsm.set_parent_commit(csmadded)
		assert nsm.module_exists()
		# in our case, the module should not exist, which happens if we update a parent
		# repo and a new submodule comes into life
		nsm.remove(configuration=False, module=True)
		assert not nsm.module_exists() and nsm.exists()
		
		
		# dry-run does nothing
		rm.update(recursive=False, dry_run=True, progress=prog)
		
		# otherwise it will work
		rm.update(recursive=False, progress=prog)
		assert nsm.module_exists()
		
		
		
		# remove submodule - the previous one
		#====================================
		sm.set_parent_commit(csmadded)
		smp = sm.abspath
		assert not sm.remove(module=False).exists()
		assert os.path.isdir(smp)			# module still exists
		csmremoved = rwrepo.index.commit("Removed submodule")
		
		# an update will remove the module
		# not in dry_run
		rm.update(recursive=False, dry_run=True)
		assert os.path.isdir(smp)
		
		rm.update(recursive=False)
		assert not os.path.isdir(smp)
		
		
		# change url 
		#=============
		# to the first repository, this way we have a fast checkout, and a completely different 
		# repository at the different url
		nsm.set_parent_commit(csmremoved)
		nsmurl = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, rsmsp[0]))
		nsm.config_writer().set_value('url', nsmurl)
		csmpathchange = rwrepo.index.commit("changed url")
		nsm.set_parent_commit(csmpathchange)
		
		prev_commit = nsm.module().head.commit
		# dry-run does nothing
		rm.update(recursive=False, dry_run=True, progress=prog)
		assert nsm.module().remotes.origin.url != nsmurl
		
		rm.update(recursive=False, progress=prog)
		assert nsm.module().remotes.origin.url == nsmurl
		# head changed, as the remote url and its commit changed
		assert prev_commit != nsm.module().head.commit
		
		# add the submodule's changed commit to the index, which is what the
		# user would do
		# beforehand, update our instance's binsha with the new one
		nsm.binsha = nsm.module().head.commit.binsha
		rwrepo.index.add([nsm])
		
		# change branch
		#=================
		# we only have one branch, so we switch to a virtual one, and back 
		# to the current one to trigger the difference
		cur_branch = nsm.branch
		nsmm = nsm.module()
		prev_commit = nsmm.head.commit
		for branch in ("some_virtual_branch", cur_branch.name):
			nsm.config_writer().set_value(Submodule.k_head_option, git.Head.to_full_path(branch))
			csmbranchchange = rwrepo.index.commit("changed branch to %s" % branch)
			nsm.set_parent_commit(csmbranchchange)
		# END for each branch to change
		
		# Lets remove our tracking branch to simulate some changes
		nsmmh = nsmm.head
		assert nsmmh.ref.tracking_branch() is None					# never set it up until now
		assert not nsmmh.is_detached
		
		#dry run does nothing
		rm.update(recursive=False, dry_run=True, progress=prog)
		assert nsmmh.ref.tracking_branch() is None
		
		# the real thing does
		rm.update(recursive=False, progress=prog)
		
		assert nsmmh.ref.tracking_branch() is not None
		assert not nsmmh.is_detached
		
		# recursive update
		# =================
		# finally we recursively update a module, just to run the code at least once
		# remove the module so that it has more work
		assert len(nsm.children()) >= 1 # could include smmap
		assert nsm.exists() and nsm.module_exists() and len(nsm.children()) >= 1
		# assure we pull locally only
		nsmc = nsm.children()[0] 
		nsmc.config_writer().set_value('url', async_url)
		rm.update(recursive=True, progress=prog, dry_run=True)		# just to run the code
		rm.update(recursive=True, progress=prog)
		
		# gitdb: has either 1 or 2 submodules depending on the version
		assert len(nsm.children()) >= 1 and nsmc.module_exists()
Exemple #2
0
    def test_root_module(self, rwrepo):
        # Can query everything without problems
        rm = RootModule(self.rorepo)
        assert rm.module() is self.rorepo

        # try attributes
        rm.binsha
        rm.mode
        rm.path
        assert rm.name == rm.k_root_name
        assert rm.parent_commit == self.rorepo.head.commit
        rm.url
        rm.branch

        assert len(rm.list_items(rm.module())) == 1
        rm.config_reader()
        with rm.config_writer():
            pass

        # deep traversal gitdb / async
        rsmsp = [sm.path for sm in rm.traverse()]
        assert len(
            rsmsp
        ) >= 2  # gitdb and async [and smmap], async being a child of gitdb

        # cannot set the parent commit as root module's path didn't exist
        self.failUnlessRaises(ValueError, rm.set_parent_commit, 'HEAD')

        # TEST UPDATE
        #############
        # setup commit which remove existing, add new and modify existing submodules
        rm = RootModule(rwrepo)
        assert len(rm.children()) == 1

        # modify path without modifying the index entry
        # ( which is what the move method would do properly )
        #==================================================
        sm = rm.children()[0]
        pp = "path/prefix"
        fp = join_path_native(pp, sm.path)
        prep = sm.path
        assert not sm.module_exists()  # was never updated after rwrepo's clone

        # assure we clone from a local source
        with sm.config_writer() as writer:
            writer.set_value(
                'url',
                Git.polish_url(osp.join(self.rorepo.working_tree_dir,
                                        sm.path)))

        # dry-run does nothing
        sm.update(recursive=False, dry_run=True, progress=prog)
        assert not sm.module_exists()

        sm.update(recursive=False)
        assert sm.module_exists()
        with sm.config_writer() as writer:
            writer.set_value(
                'path',
                fp)  # change path to something with prefix AFTER url change

        # update doesn't fail, because list_items ignores the wrong path in such situations.
        rm.update(recursive=False)

        # move it properly - doesn't work as it its path currently points to an indexentry
        # which doesn't exist ( move it to some path, it doesn't matter here )
        self.failUnlessRaises(InvalidGitRepositoryError, sm.move, pp)
        # reset the path(cache) to where it was, now it works
        sm.path = prep
        sm.move(fp, module=False)  # leave it at the old location

        assert not sm.module_exists()
        cpathchange = rwrepo.index.commit(
            "changed sm path")  # finally we can commit

        # update puts the module into place
        rm.update(recursive=False, progress=prog)
        sm.set_parent_commit(cpathchange)
        assert sm.module_exists()

        # add submodule
        #================
        nsmn = "newsubmodule"
        nsmp = "submrepo"
        subrepo_url = Git.polish_url(
            osp.join(self.rorepo.working_tree_dir, rsmsp[0], rsmsp[1]))
        nsm = Submodule.add(rwrepo, nsmn, nsmp, url=subrepo_url)
        csmadded = rwrepo.index.commit(
            "Added submodule"
        ).hexsha  # make sure we don't keep the repo reference
        nsm.set_parent_commit(csmadded)
        assert nsm.module_exists()
        # in our case, the module should not exist, which happens if we update a parent
        # repo and a new submodule comes into life
        nsm.remove(configuration=False, module=True)
        assert not nsm.module_exists() and nsm.exists()

        # dry-run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)

        # otherwise it will work
        rm.update(recursive=False, progress=prog)
        assert nsm.module_exists()

        # remove submodule - the previous one
        #====================================
        sm.set_parent_commit(csmadded)
        smp = sm.abspath
        assert not sm.remove(module=False).exists()
        assert osp.isdir(smp)  # module still exists
        csmremoved = rwrepo.index.commit("Removed submodule")

        # an update will remove the module
        # not in dry_run
        rm.update(recursive=False, dry_run=True, force_remove=True)
        assert osp.isdir(smp)

        # when removing submodules, we may get new commits as nested submodules are auto-committing changes
        # to allow deletions without force, as the index would be dirty otherwise.
        # QUESTION: Why does this seem to work in test_git_submodule_compatibility() ?
        self.failUnlessRaises(InvalidGitRepositoryError,
                              rm.update,
                              recursive=False,
                              force_remove=False)
        rm.update(recursive=False, force_remove=True)
        assert not osp.isdir(smp)

        # 'apply work' to the nested submodule and assure this is not removed/altered during updates
        # Need to commit first, otherwise submodule.update wouldn't have a reason to change the head
        touch(osp.join(nsm.module().working_tree_dir, 'new-file'))
        # We cannot expect is_dirty to even run as we wouldn't reset a head to the same location
        assert nsm.module().head.commit.hexsha == nsm.hexsha
        nsm.module().index.add([nsm])
        nsm.module().index.commit("added new file")
        rm.update(
            recursive=False, dry_run=True,
            progress=prog)  # would not change head, and thus doens't fail
        # Everything we can do from now on will trigger the 'future' check, so no is_dirty() check will even run
        # This would only run if our local branch is in the past and we have uncommitted changes

        prev_commit = nsm.module().head.commit
        rm.update(recursive=False, dry_run=False, progress=prog)
        assert prev_commit == nsm.module(
        ).head.commit, "head shouldn't change, as it is in future of remote branch"

        # this kills the new file
        rm.update(recursive=True, progress=prog, force_reset=True)
        assert prev_commit != nsm.module(
        ).head.commit, "head changed, as the remote url and its commit changed"

        # change url ...
        #===============
        # ... to the first repository, this way we have a fast checkout, and a completely different
        # repository at the different url
        nsm.set_parent_commit(csmremoved)
        nsmurl = Git.polish_url(
            osp.join(self.rorepo.working_tree_dir, rsmsp[0]))
        with nsm.config_writer() as writer:
            writer.set_value('url', nsmurl)
        csmpathchange = rwrepo.index.commit("changed url")
        nsm.set_parent_commit(csmpathchange)

        # Now nsm head is in the future of the tracked remote branch
        prev_commit = nsm.module().head.commit
        # dry-run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)
        assert nsm.module().remotes.origin.url != nsmurl

        rm.update(recursive=False, progress=prog, force_reset=True)
        assert nsm.module().remotes.origin.url == nsmurl
        assert prev_commit != nsm.module(
        ).head.commit, "Should now point to gitdb"
        assert len(rwrepo.submodules) == 1
        assert not rwrepo.submodules[0].children()[0].module_exists(
        ), "nested submodule should not be checked out"

        # add the submodule's changed commit to the index, which is what the
        # user would do
        # beforehand, update our instance's binsha with the new one
        nsm.binsha = nsm.module().head.commit.binsha
        rwrepo.index.add([nsm])

        # change branch
        #=================
        # we only have one branch, so we switch to a virtual one, and back
        # to the current one to trigger the difference
        cur_branch = nsm.branch
        nsmm = nsm.module()
        prev_commit = nsmm.head.commit
        for branch in ("some_virtual_branch", cur_branch.name):
            with nsm.config_writer() as writer:
                writer.set_value(Submodule.k_head_option,
                                 git.Head.to_full_path(branch))
            csmbranchchange = rwrepo.index.commit("changed branch to %s" %
                                                  branch)
            nsm.set_parent_commit(csmbranchchange)
        # END for each branch to change

        # Lets remove our tracking branch to simulate some changes
        nsmmh = nsmm.head
        assert nsmmh.ref.tracking_branch() is None  # never set it up until now
        assert not nsmmh.is_detached

        # dry run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)
        assert nsmmh.ref.tracking_branch() is None

        # the real thing does
        rm.update(recursive=False, progress=prog)

        assert nsmmh.ref.tracking_branch() is not None
        assert not nsmmh.is_detached

        # recursive update
        # =================
        # finally we recursively update a module, just to run the code at least once
        # remove the module so that it has more work
        assert len(nsm.children()) >= 1  # could include smmap
        assert nsm.exists() and nsm.module_exists() and len(
            nsm.children()) >= 1
        # assure we pull locally only
        nsmc = nsm.children()[0]
        with nsmc.config_writer() as writer:
            writer.set_value('url', subrepo_url)
        rm.update(recursive=True, progress=prog,
                  dry_run=True)  # just to run the code
        rm.update(recursive=True, progress=prog)

        # gitdb: has either 1 or 2 submodules depending on the version
        assert len(nsm.children()) >= 1 and nsmc.module_exists()
Exemple #3
0
    def test_root_module(self, rwrepo):
        # Can query everything without problems
        rm = RootModule(self.rorepo)
        assert rm.module() is self.rorepo

        # try attributes
        rm.binsha
        rm.mode
        rm.path
        assert rm.name == rm.k_root_name
        assert rm.parent_commit == self.rorepo.head.commit
        rm.url
        rm.branch

        assert len(rm.list_items(rm.module())) == 1
        rm.config_reader()
        rm.config_writer()

        # deep traversal gitdb / async
        rsmsp = [sm.path for sm in rm.traverse()]
        assert len(rsmsp) == 2  # gitdb and async, async being a child of gitdb

        # cannot set the parent commit as root module's path didn't exist
        self.failUnlessRaises(ValueError, rm.set_parent_commit, 'HEAD')

        # TEST UPDATE
        #############
        # setup commit which remove existing, add new and modify existing submodules
        rm = RootModule(rwrepo)
        assert len(rm.children()) == 1

        # modify path without modifying the index entry
        # ( which is what the move method would do properly )
        #==================================================
        sm = rm.children()[0]
        pp = "path/prefix"
        fp = join_path_native(pp, sm.path)
        prep = sm.path
        assert not sm.module_exists()  # was never updated after rwrepo's clone

        # assure we clone from a local source
        sm.config_writer().set_value(
            'url',
            to_native_path_linux(
                join_path_native(self.rorepo.working_tree_dir, sm.path)))

        # dry-run does nothing
        sm.update(recursive=False, dry_run=True, progress=prog)
        assert not sm.module_exists()

        sm.update(recursive=False)
        assert sm.module_exists()
        sm.config_writer().set_value(
            'path',
            fp)  # change path to something with prefix AFTER url change

        # update fails as list_items in such a situations cannot work, as it cannot
        # find the entry at the changed path
        self.failUnlessRaises(InvalidGitRepositoryError,
                              rm.update,
                              recursive=False)

        # move it properly - doesn't work as it its path currently points to an indexentry
        # which doesn't exist ( move it to some path, it doesn't matter here )
        self.failUnlessRaises(InvalidGitRepositoryError, sm.move, pp)
        # reset the path(cache) to where it was, now it works
        sm.path = prep
        sm.move(fp, module=False)  # leave it at the old location

        assert not sm.module_exists()
        cpathchange = rwrepo.index.commit(
            "changed sm path")  # finally we can commit

        # update puts the module into place
        rm.update(recursive=False, progress=prog)
        sm.set_parent_commit(cpathchange)
        assert sm.module_exists()

        # add submodule
        #================
        nsmn = "newsubmodule"
        nsmp = "submrepo"
        async_url = to_native_path_linux(
            join_path_native(self.rorepo.working_tree_dir, rsmsp[0], rsmsp[1]))
        nsm = Submodule.add(rwrepo, nsmn, nsmp, url=async_url)
        csmadded = rwrepo.index.commit(
            "Added submodule"
        ).hexsha  # make sure we don't keep the repo reference
        nsm.set_parent_commit(csmadded)
        assert nsm.module_exists()
        # in our case, the module should not exist, which happens if we update a parent
        # repo and a new submodule comes into life
        nsm.remove(configuration=False, module=True)
        assert not nsm.module_exists() and nsm.exists()

        # dry-run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)

        # otherwise it will work
        rm.update(recursive=False, progress=prog)
        assert nsm.module_exists()

        # remove submodule - the previous one
        #====================================
        sm.set_parent_commit(csmadded)
        smp = sm.abspath
        assert not sm.remove(module=False).exists()
        assert os.path.isdir(smp)  # module still exists
        csmremoved = rwrepo.index.commit("Removed submodule")

        # an update will remove the module
        # not in dry_run
        rm.update(recursive=False, dry_run=True)
        assert os.path.isdir(smp)

        rm.update(recursive=False)
        assert not os.path.isdir(smp)

        # change url
        #=============
        # to the first repository, this way we have a fast checkout, and a completely different
        # repository at the different url
        nsm.set_parent_commit(csmremoved)
        nsmurl = to_native_path_linux(
            join_path_native(self.rorepo.working_tree_dir, rsmsp[0]))
        nsm.config_writer().set_value('url', nsmurl)
        csmpathchange = rwrepo.index.commit("changed url")
        nsm.set_parent_commit(csmpathchange)

        prev_commit = nsm.module().head.commit
        # dry-run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)
        assert nsm.module().remotes.origin.url != nsmurl

        rm.update(recursive=False, progress=prog)
        assert nsm.module().remotes.origin.url == nsmurl
        # head changed, as the remote url and its commit changed
        assert prev_commit != nsm.module().head.commit

        # add the submodule's changed commit to the index, which is what the
        # user would do
        # beforehand, update our instance's binsha with the new one
        nsm.binsha = nsm.module().head.commit.binsha
        rwrepo.index.add([nsm])

        # change branch
        #=================
        # we only have one branch, so we switch to a virtual one, and back
        # to the current one to trigger the difference
        cur_branch = nsm.branch
        nsmm = nsm.module()
        prev_commit = nsmm.head.commit
        for branch in ("some_virtual_branch", cur_branch.name):
            nsm.config_writer().set_value(Submodule.k_head_option,
                                          git.Head.to_full_path(branch))
            csmbranchchange = rwrepo.index.commit("changed branch to %s" %
                                                  branch)
            nsm.set_parent_commit(csmbranchchange)
        # END for each branch to change

        # Lets remove our tracking branch to simulate some changes
        nsmmh = nsmm.head
        assert nsmmh.ref.tracking_branch() is None  # never set it up until now
        assert not nsmmh.is_detached

        #dry run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)
        assert nsmmh.ref.tracking_branch() is None

        # the real thing does
        rm.update(recursive=False, progress=prog)

        assert nsmmh.ref.tracking_branch() is not None
        assert not nsmmh.is_detached

        # recursive update
        # =================
        # finally we recursively update a module, just to run the code at least once
        # remove the module so that it has more work
        assert len(nsm.children()) == 1
        assert nsm.exists() and nsm.module_exists() and len(
            nsm.children()) == 1
        # assure we pull locally only
        nsmc = nsm.children()[0]
        nsmc.config_writer().set_value('url', async_url)
        rm.update(recursive=True, progress=prog,
                  dry_run=True)  # just to run the code
        rm.update(recursive=True, progress=prog)

        assert len(nsm.children()) == 1 and nsmc.module_exists()
    def test_root_module(self, rwrepo):
        # Can query everything without problems
        rm = RootModule(self.rorepo)
        assert rm.module() is self.rorepo

        # try attributes
        rm.binsha
        rm.mode
        rm.path
        assert rm.name == rm.k_root_name
        assert rm.parent_commit == self.rorepo.head.commit
        rm.url
        rm.branch

        assert len(rm.list_items(rm.module())) == 1
        rm.config_reader()
        with rm.config_writer():
            pass

        # deep traversal gitdb / async
        rsmsp = [sm.path for sm in rm.traverse()]
        assert len(rsmsp) >= 2          # gitdb and async [and smmap], async being a child of gitdb

        # cannot set the parent commit as root module's path didn't exist
        self.failUnlessRaises(ValueError, rm.set_parent_commit, 'HEAD')

        # TEST UPDATE
        #############
        # setup commit which remove existing, add new and modify existing submodules
        rm = RootModule(rwrepo)
        assert len(rm.children()) == 1

        # modify path without modifying the index entry
        # ( which is what the move method would do properly )
        #==================================================
        sm = rm.children()[0]
        pp = "path/prefix"
        fp = join_path_native(pp, sm.path)
        prep = sm.path
        assert not sm.module_exists()               # was never updated after rwrepo's clone

        # assure we clone from a local source
        with sm.config_writer() as writer:
            writer.set_value('url', Git.polish_url(osp.join(self.rorepo.working_tree_dir, sm.path)))

        # dry-run does nothing
        sm.update(recursive=False, dry_run=True, progress=prog)
        assert not sm.module_exists()

        sm.update(recursive=False)
        assert sm.module_exists()
        with sm.config_writer() as writer:
            writer.set_value('path', fp)    # change path to something with prefix AFTER url change

        # update fails as list_items in such a situations cannot work, as it cannot
        # find the entry at the changed path
        self.failUnlessRaises(InvalidGitRepositoryError, rm.update, recursive=False)

        # move it properly - doesn't work as it its path currently points to an indexentry
        # which doesn't exist ( move it to some path, it doesn't matter here )
        self.failUnlessRaises(InvalidGitRepositoryError, sm.move, pp)
        # reset the path(cache) to where it was, now it works
        sm.path = prep
        sm.move(fp, module=False)       # leave it at the old location

        assert not sm.module_exists()
        cpathchange = rwrepo.index.commit("changed sm path")  # finally we can commit

        # update puts the module into place
        rm.update(recursive=False, progress=prog)
        sm.set_parent_commit(cpathchange)
        assert sm.module_exists()

        # add submodule
        #================
        nsmn = "newsubmodule"
        nsmp = "submrepo"
        subrepo_url = Git.polish_url(osp.join(self.rorepo.working_tree_dir, rsmsp[0], rsmsp[1]))
        nsm = Submodule.add(rwrepo, nsmn, nsmp, url=subrepo_url)
        csmadded = rwrepo.index.commit("Added submodule").hexsha    # make sure we don't keep the repo reference
        nsm.set_parent_commit(csmadded)
        assert nsm.module_exists()
        # in our case, the module should not exist, which happens if we update a parent
        # repo and a new submodule comes into life
        nsm.remove(configuration=False, module=True)
        assert not nsm.module_exists() and nsm.exists()

        # dry-run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)

        # otherwise it will work
        rm.update(recursive=False, progress=prog)
        assert nsm.module_exists()

        # remove submodule - the previous one
        #====================================
        sm.set_parent_commit(csmadded)
        smp = sm.abspath
        assert not sm.remove(module=False).exists()
        assert osp.isdir(smp)           # module still exists
        csmremoved = rwrepo.index.commit("Removed submodule")

        # an update will remove the module
        # not in dry_run
        rm.update(recursive=False, dry_run=True, force_remove=True)
        assert osp.isdir(smp)

        # when removing submodules, we may get new commits as nested submodules are auto-committing changes
        # to allow deletions without force, as the index would be dirty otherwise.
        # QUESTION: Why does this seem to work in test_git_submodule_compatibility() ?
        self.failUnlessRaises(InvalidGitRepositoryError, rm.update, recursive=False, force_remove=False)
        rm.update(recursive=False, force_remove=True)
        assert not osp.isdir(smp)

        # 'apply work' to the nested submodule and assure this is not removed/altered during updates
        # Need to commit first, otherwise submodule.update wouldn't have a reason to change the head
        touch(osp.join(nsm.module().working_tree_dir, 'new-file'))
        # We cannot expect is_dirty to even run as we wouldn't reset a head to the same location
        assert nsm.module().head.commit.hexsha == nsm.hexsha
        nsm.module().index.add([nsm])
        nsm.module().index.commit("added new file")
        rm.update(recursive=False, dry_run=True, progress=prog)  # would not change head, and thus doens't fail
        # Everything we can do from now on will trigger the 'future' check, so no is_dirty() check will even run
        # This would only run if our local branch is in the past and we have uncommitted changes

        prev_commit = nsm.module().head.commit
        rm.update(recursive=False, dry_run=False, progress=prog)
        assert prev_commit == nsm.module().head.commit, "head shouldn't change, as it is in future of remote branch"

        # this kills the new file
        rm.update(recursive=True, progress=prog, force_reset=True)
        assert prev_commit != nsm.module().head.commit, "head changed, as the remote url and its commit changed"

        # change url ...
        #===============
        # ... to the first repository, this way we have a fast checkout, and a completely different
        # repository at the different url
        nsm.set_parent_commit(csmremoved)
        nsmurl = Git.polish_url(osp.join(self.rorepo.working_tree_dir, rsmsp[0]))
        with nsm.config_writer() as writer:
            writer.set_value('url', nsmurl)
        csmpathchange = rwrepo.index.commit("changed url")
        nsm.set_parent_commit(csmpathchange)

        # Now nsm head is in the future of the tracked remote branch
        prev_commit = nsm.module().head.commit
        # dry-run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)
        assert nsm.module().remotes.origin.url != nsmurl

        rm.update(recursive=False, progress=prog, force_reset=True)
        assert nsm.module().remotes.origin.url == nsmurl
        assert prev_commit != nsm.module().head.commit, "Should now point to gitdb"
        assert len(rwrepo.submodules) == 1
        assert not rwrepo.submodules[0].children()[0].module_exists(), "nested submodule should not be checked out"

        # add the submodule's changed commit to the index, which is what the
        # user would do
        # beforehand, update our instance's binsha with the new one
        nsm.binsha = nsm.module().head.commit.binsha
        rwrepo.index.add([nsm])

        # change branch
        #=================
        # we only have one branch, so we switch to a virtual one, and back
        # to the current one to trigger the difference
        cur_branch = nsm.branch
        nsmm = nsm.module()
        prev_commit = nsmm.head.commit
        for branch in ("some_virtual_branch", cur_branch.name):
            with nsm.config_writer() as writer:
                writer.set_value(Submodule.k_head_option, git.Head.to_full_path(branch))
            csmbranchchange = rwrepo.index.commit("changed branch to %s" % branch)
            nsm.set_parent_commit(csmbranchchange)
        # END for each branch to change

        # Lets remove our tracking branch to simulate some changes
        nsmmh = nsmm.head
        assert nsmmh.ref.tracking_branch() is None                  # never set it up until now
        assert not nsmmh.is_detached

        # dry run does nothing
        rm.update(recursive=False, dry_run=True, progress=prog)
        assert nsmmh.ref.tracking_branch() is None

        # the real thing does
        rm.update(recursive=False, progress=prog)

        assert nsmmh.ref.tracking_branch() is not None
        assert not nsmmh.is_detached

        # recursive update
        # =================
        # finally we recursively update a module, just to run the code at least once
        # remove the module so that it has more work
        assert len(nsm.children()) >= 1  # could include smmap
        assert nsm.exists() and nsm.module_exists() and len(nsm.children()) >= 1
        # assure we pull locally only
        nsmc = nsm.children()[0]
        with nsmc.config_writer() as writer:
            writer.set_value('url', subrepo_url)
        rm.update(recursive=True, progress=prog, dry_run=True)      # just to run the code
        rm.update(recursive=True, progress=prog)

        # gitdb: has either 1 or 2 submodules depending on the version
        assert len(nsm.children()) >= 1 and nsmc.module_exists()