summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--git/objects/submodule/base.py12
-rw-r--r--git/objects/submodule/root.py25
-rw-r--r--git/objects/submodule/util.py2
-rw-r--r--git/repo/fun.py1
-rw-r--r--git/test/test_submodule.py67
5 files changed, 77 insertions, 30 deletions
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index 4b2fc0c0..ebb66495 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -411,21 +411,9 @@ class Submodule(util.IndexObject, Iterable, Traversable):
del(writer)
# we deliberatly assume that our head matches our index !
-
- try:
- repo.head.commit
- parent_repo_is_empty = False
- except ValueError:
- parent_repo_is_empty = True
- # Can't set this yet, if the parent repo is empty.
- # end
sm.binsha = mrepo.head.commit.binsha
index.add([sm], write=True)
- if parent_repo_is_empty:
- log.debug("Will not set _parent_commit now as the parent repository has no commit yet.")
- # end
-
return sm
def update(self, recursive=False, init=True, to_latest_revision=False, progress=None, dry_run=False,
diff --git a/git/objects/submodule/root.py b/git/objects/submodule/root.py
index 7042e99c..1c863f6f 100644
--- a/git/objects/submodule/root.py
+++ b/git/objects/submodule/root.py
@@ -287,6 +287,11 @@ class RootModule(Submodule):
if not dry_run:
smm = sm.module()
smmr = smm.remotes
+ # As the branch might not exist yet, we will have to fetch all remotes to be sure ... .
+ for remote in smmr:
+ remote.fetch(progress=progress)
+ # end for each remote
+
try:
tbr = git.Head.create(smm, sm.branch_name, logmsg='branch: Created from HEAD')
except OSError:
@@ -295,21 +300,11 @@ class RootModule(Submodule):
# END assure tracking branch exists
tbr.set_tracking_branch(find_first_remote_branch(smmr, sm.branch_name))
- # figure out whether the previous tracking branch contains
- # new commits compared to the other one, if not we can
- # delete it.
- try:
- tbr = find_first_remote_branch(smmr, psm.branch_name)
- if len(smm.git.cherry(tbr, psm.branch)) == 0:
- psm.branch.delete(smm, psm.branch)
- # END delete original tracking branch if there are no changes
- except InvalidGitRepositoryError:
- # ignore it if the previous branch couldn't be found in the
- # current remotes, this just means we can't handle it
- pass
- # END exception handling
-
- # NOTE: All checkout is done in the base implementation of update
+ # NOTE: All head-resetting is done in the base implementation of update
+ # but we will have to checkout the new branch here. As it still points to the currently
+ # checkout out commit, we don't do any harm.
+ # As we don't want to update working-tree or index, changing the ref is all there is to do
+ smm.head.reference = tbr
# END handle dry_run
progress.update(
diff --git a/git/objects/submodule/util.py b/git/objects/submodule/util.py
index 5604dec7..8b9873fc 100644
--- a/git/objects/submodule/util.py
+++ b/git/objects/submodule/util.py
@@ -49,7 +49,7 @@ def find_first_remote_branch(remotes, branch_name):
continue
# END exception handling
# END for remote
- raise InvalidGitRepositoryError("Didn't find remote branch %r in any of the given remotes", branch_name)
+ raise InvalidGitRepositoryError("Didn't find remote branch '%r' in any of the given remotes" % branch_name)
#} END utilities
diff --git a/git/repo/fun.py b/git/repo/fun.py
index 2a1270be..2321dbc8 100644
--- a/git/repo/fun.py
+++ b/git/repo/fun.py
@@ -26,6 +26,7 @@ __all__ = ('rev_parse', 'is_git_dir', 'touch', 'find_git_dir', 'name_to_object',
def touch(filename):
fp = open(filename, "ab")
fp.close()
+ return filename
def is_git_dir(d):
diff --git a/git/test/test_submodule.py b/git/test/test_submodule.py
index 6a03fe26..49ab2586 100644
--- a/git/test/test_submodule.py
+++ b/git/test/test_submodule.py
@@ -529,10 +529,9 @@ class TestSubmodule(TestBase):
# '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
- nsm_file = os.path.join(nsm.module().working_tree_dir, 'new-file')
+ touch(os.path.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
- touch(nsm_file)
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
@@ -778,3 +777,67 @@ class TestSubmodule(TestBase):
if os.path.isfile(os.path.join(sm_mod.working_tree_dir, '.git')) == sm._need_gitfile_submodules(parent.git):
assert sm_mod.git_dir.endswith(".git/modules/" + new_sm_name)
# end
+
+ @with_rw_directory
+ def test_branch_renames(self, rw_dir):
+ # Setup initial sandbox:
+ # parent repo has one submodule, which has all the latest changes
+ source_url = self._submodule_url()
+ sm_source_repo = git.Repo.clone_from(source_url, os.path.join(rw_dir, 'sm-source'))
+ parent_repo = git.Repo.init(os.path.join(rw_dir, 'parent'))
+ sm = parent_repo.create_submodule('mysubmodule', 'subdir/submodule',
+ sm_source_repo.working_tree_dir, branch='master')
+ parent_repo.index.commit('added submodule')
+ assert sm.exists()
+
+ # Create feature branch with one new commit in submodule source
+ sm_fb = sm_source_repo.create_head('feature')
+ sm_fb.checkout()
+ new_file = touch(os.path.join(sm_source_repo.working_tree_dir, 'new-file'))
+ sm_source_repo.index.add([new_file])
+ sm.repo.index.commit("added new file")
+
+ # change designated submodule checkout branch to the new upstream feature branch
+ smcw = sm.config_writer()
+ smcw.set_value('branch', sm_fb.name)
+ smcw.release()
+ assert sm.repo.is_dirty(index=True, working_tree=False)
+ sm.repo.index.commit("changed submodule branch to '%s'" % sm_fb)
+
+ # verify submodule update with feature branch that leaves currently checked out branch in it's past
+ sm_mod = sm.module()
+ prev_commit = sm_mod.commit()
+ assert sm_mod.head.ref.name == 'master'
+ assert parent_repo.submodule_update()
+ assert sm_mod.head.ref.name == sm_fb.name
+ assert sm_mod.commit() == prev_commit, "Without to_latest_revision, we don't change the commit"
+
+ assert parent_repo.submodule_update(to_latest_revision=True)
+ assert sm_mod.head.ref.name == sm_fb.name
+ assert sm_mod.commit() == sm_fb.commit
+
+ # Create new branch which is in our past, and thus seemingly unrelated to the currently checked out one
+ # To make it even 'harder', we shall fork and create a new commit
+ sm_pfb = sm_source_repo.create_head('past-feature', commit='HEAD~20')
+ sm_pfb.checkout()
+ sm_source_repo.index.add([touch(os.path.join(sm_source_repo.working_tree_dir, 'new-file'))])
+ sm_source_repo.index.commit("new file added, to past of '%r'" % sm_fb)
+
+ # Change designated submodule checkout branch to a new commit in its own past
+ smcw = sm.config_writer()
+ smcw.set_value('branch', sm_pfb.path)
+ smcw.release()
+ sm.repo.index.commit("changed submodule branch to '%s'" % sm_pfb)
+
+ # Test submodule updates - must fail if submodule is dirty
+ touch(os.path.join(sm_mod.working_tree_dir, 'unstaged file'))
+ # This doesn't fail as our own submodule binsha didn't change, and the reset is only triggered if
+ # to latest revision is True.
+ parent_repo.submodule_update(to_latest_revision=False)
+ sm_mod.head.ref.name == sm_pfb.name, "should have been switched to past head"
+ sm_mod.commit() == sm_fb.commit, "Head wasn't reset"
+
+ self.failUnlessRaises(RepositoryDirtyError, parent_repo.submodule_update, to_latest_revision=True)
+ parent_repo.submodule_update(to_latest_revision=True, force_reset=True)
+ assert sm_mod.commit() == sm_pfb.commit, "Now head should have been reset"
+ assert sm_mod.head.ref.name == sm_pfb.name