Skip to content

Commit 78d2cd6

Browse files
committed
implemented update to_last_revision option including test. Its now possible to update submodules such as svn-externals
1 parent 21b4db5 commit 78d2cd6

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

lib/git/objects/submodule.py

+37-6
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,26 @@ def add(cls, repo, path, url, skip_init=False):
211211
:param skip_init: if True, the new repository will not be cloned to its location.
212212
:return: The newly created submodule instance"""
213213

214-
def update(self, recursive=False, init=True):
214+
def update(self, recursive=False, init=True, to_latest_revision=False):
215215
"""Update the repository of this submodule to point to the checkout
216216
we point at with the binsha of this instance.
217217
:param recursive: if True, we will operate recursively and update child-
218218
modules as well.
219219
:param init: if True, the module repository will be cloned into place if necessary
220+
:param to_latest_revision: if True, the submodule's sha will be ignored during checkout.
221+
Instead, the remote will be fetched, and the local tracking branch updated.
222+
This only works if we have a local tracking branch, which is the case
223+
if the remote repository had a master branch, or of the 'branch' option
224+
was specified for this submodule and the branch existed remotely
220225
:note: does nothing in bare repositories
221226
:return: self"""
222227
if self.repo.bare:
223228
return self
224229
#END pass in bare mode
225230

231+
232+
# ASSURE REPO IS PRESENT AND UPTODATE
233+
#####################################
226234
try:
227235
mrepo = self.module()
228236
for remote in mrepo.remotes:
@@ -277,22 +285,45 @@ def update(self, recursive=False, init=True):
277285
#END handle tracking branch
278286
#END handle initalization
279287

288+
289+
# DETERMINE SHAS TO CHECKOUT
290+
############################
291+
binsha = self.binsha
292+
hexsha = self.hexsha
293+
is_detached = mrepo.head.is_detached
294+
if to_latest_revision:
295+
msg_base = "Cannot update to latest revision in repository at %r as " % mrepo.working_dir
296+
if not is_detached:
297+
rref = mrepo.head.ref.tracking_branch()
298+
if rref is not None:
299+
rcommit = rref.commit
300+
binsha = rcommit.binsha
301+
hexsha = rcommit.hexsha
302+
else:
303+
print >> sys.stderr, "%s a tracking branch was not set for local branch '%s'" % (msg_base, mrepo.head.ref)
304+
# END handle remote ref
305+
else:
306+
print >> sys.stderr, "%s there was no local tracking branch" % msg_base
307+
# END handle detached head
308+
# END handle to_latest_revision option
309+
280310
# update the working tree
281-
if mrepo.head.commit.binsha != self.binsha:
282-
if mrepo.head.is_detached:
283-
mrepo.git.checkout(self.hexsha)
311+
if mrepo.head.commit.binsha != binsha:
312+
if is_detached:
313+
mrepo.git.checkout(hexsha)
284314
else:
285315
# TODO: allow to specify a rebase, merge, or reset
286316
# TODO: Warn if the hexsha forces the tracking branch off the remote
287317
# branch - this should be prevented when setting the branch option
288-
mrepo.head.reset(self.hexsha, index=True, working_tree=True)
318+
mrepo.head.reset(hexsha, index=True, working_tree=True)
289319
# END handle checkout
290320
# END update to new commit only if needed
291321

292322
# HANDLE RECURSION
323+
##################
293324
if recursive:
294325
for submodule in self.iter_items(self.module()):
295-
submodule.update(recursive, init)
326+
submodule.update(recursive, init, to_latest_revision)
296327
# END handle recursive update
297328
# END for each submodule
298329

test/git/test_submodule.py

+23
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,29 @@ def _do_base_tests(self, rwrepo):
132132

133133
# this flushed in a sub-submodule
134134
assert len(list(rwrepo.iter_submodules())) == 2
135+
136+
137+
# reset both heads to the previous version, verify that to_latest_revision works
138+
for repo in (csm.module(), sm.module()):
139+
repo.head.reset('HEAD~1', working_tree=1)
140+
# END for each repo to reset
141+
142+
sm.update(recursive=True, to_latest_revision=True)
143+
for repo in (sm.module(), csm.module()):
144+
assert repo.head.commit == repo.head.ref.tracking_branch().commit
145+
# END for each repo to check
146+
147+
# if the head is detached, it still works ( but warns )
148+
smref = sm.module().head.ref
149+
sm.module().head.ref = 'HEAD~1'
150+
# if there is no tracking branch, we get a warning as well
151+
csm_tracking_branch = csm.module().head.ref.tracking_branch()
152+
csm.module().head.ref.set_tracking_branch(None)
153+
sm.update(recursive=True, to_latest_revision=True)
154+
155+
# undo the changes
156+
sm.module().head.ref = smref
157+
csm.module().head.ref.set_tracking_branch(csm_tracking_branch)
135158
# END handle bare mode
136159

137160

0 commit comments

Comments
 (0)