@@ -202,15 +202,101 @@ def _config_parser_constrained(self, read_only):
202
202
#{ Edit Interface
203
203
204
204
@classmethod
205
- def add (cls , repo , path , url , skip_init = False ):
205
+ def add (cls , repo , name , path , url = None , branch = k_head_default , no_checkout = False ):
206
206
"""Add a new submodule to the given repository. This will alter the index
207
207
as well as the .gitmodules file, but will not create a new commit.
208
+ If the submodule already exists, no matter if the configuration differs
209
+ from the one provided, the existing submodule will be returned.
208
210
:param repo: Repository instance which should receive the submodule
209
- :param path: repository-relative path at which the submodule should be located
211
+ :param name: The name/identifier for the submodule
212
+ :param path: repository-relative or absolute path at which the submodule
213
+ should be located
210
214
It will be created as required during the repository initialization.
211
215
:param url: git-clone compatible URL, see git-clone reference for more information
212
- :param skip_init: if True, the new repository will not be cloned to its location.
213
- :return: The newly created submodule instance"""
216
+ If None, the repository is assumed to exist, and the url of the first
217
+ remote is taken instead. This is useful if you want to make an existing
218
+ repository a submodule of anotherone.
219
+ :param branch: branch at which the submodule should (later) be checked out.
220
+ The given branch must exist in the remote repository, and will be checked
221
+ out locally as a tracking branch.
222
+ It will only be written into the configuration if it differs from the
223
+ default.
224
+ :param no_checkout: if True, and if the repository has to be cloned manually,
225
+ no checkout will be performed
226
+ :return: The newly created submodule instance
227
+ :note: works atomically, such that no change will be done if the repository
228
+ update fails for instance"""
229
+ if repo .bare :
230
+ raise InvalidGitRepositoryError ("Cannot add a submodule to bare repositories" )
231
+ #END handle bare mode
232
+
233
+ path = to_native_path_linux (path )
234
+ if path .endswith ('/' ):
235
+ path = path [:- 1 ]
236
+ # END handle trailing slash
237
+
238
+ sm = cls (repo , cls .NULL_BIN_SHA , cls .k_def_mode , path , name )
239
+ if sm .exists ():
240
+ # reretrieve submodule from tree
241
+ return repo .head .commit .tree [path ]
242
+ # END handle existing
243
+
244
+ branch = Head (repo , head .to_full_path (branch ))
245
+ has_module = sm .module_exists ()
246
+ branch_is_default = branch .name == cls .k_head_default
247
+ if has_module and url is not None :
248
+ if url not in [r .url for r in sm .module ().remotes ]:
249
+ raise ValueError ("Specified URL %s does not match any remote url of the repository at %s" % (url , sm .module_path ()))
250
+ # END check url
251
+ # END verify urls match
252
+
253
+ mrepo = None
254
+ if url is None :
255
+ if not has_module :
256
+ raise ValueError ("A URL was not given and existing repository did not exsit at %s" % path )
257
+ # END check url
258
+ mrepo = sm .module ()
259
+ urls = [r .url for r in mrepo .remotes ]
260
+ if not urls :
261
+ raise ValueError ("Didn't find any remote url in repository at %s" % sm .module_path ())
262
+ # END verify we have url
263
+ url = urls [0 ]
264
+ else :
265
+ # clone new repo
266
+ kwargs = {'n' : no_checkout }
267
+ if branch_is_default :
268
+ kwargs ['b' ] = str (branch )
269
+ # END setup checkout-branch
270
+ mrepo = git .Repo .clone_from (url , path , ** kwargs )
271
+ # END verify url
272
+
273
+ # update configuration and index
274
+ writer = sm .config_writer ()
275
+ writer .set_value ('url' , url )
276
+ writer .set_value ('path' , path )
277
+
278
+ sm ._url = url
279
+ if not branch_is_default :
280
+ # store full path
281
+ writer .set_value (cls .k_head_option , branch .path )
282
+ sm ._branch = branch
283
+ # END handle path
284
+ del (writer )
285
+
286
+ # NOTE: Have to write the repo config file as well, otherwise
287
+ # the default implementation will be offended and not update the repository
288
+ # Maybe this is a good way to assure it doesn't get into our way, but
289
+ # we want to stay backwards compatible too ... . Its so redundant !
290
+ repo .config_writer ().set_value (sm_section (sm .name ), 'url' , url )
291
+
292
+ # we deliberatly assume that our head matches our index !
293
+ pcommit = repo .head .commit
294
+ sm ._parent_commit = pcommit
295
+ sm .binsha = mrepo .head .commit .binsha
296
+ repo .index .add ([sm ], write = True )
297
+
298
+ return sm
299
+
214
300
215
301
def update (self , recursive = False , init = True , to_latest_revision = False ):
216
302
"""Update the repository of this submodule to point to the checkout
0 commit comments