@@ -189,58 +189,119 @@ static int canonicalize_url(git_buf *out, const char *in)
189189 return git_buf_puts (out , in );
190190}
191191
192- static int create_internal ( git_remote * * out , git_repository * repo , const char * name , const char * url , const char * fetch )
192+ static int default_fetchspec_for_name ( git_buf * buf , const char * name )
193193{
194+ if (git_buf_printf (buf , "+refs/heads/*:refs/remotes/%s/*" , name ) < 0 )
195+ return -1 ;
196+
197+ return 0 ;
198+ }
199+
200+ static int ensure_remote_doesnot_exist (git_repository * repo , const char * name )
201+ {
202+ int error ;
194203 git_remote * remote ;
204+
205+ error = git_remote_lookup (& remote , repo , name );
206+
207+ if (error == GIT_ENOTFOUND )
208+ return 0 ;
209+
210+ if (error < 0 )
211+ return error ;
212+
213+ git_remote_free (remote );
214+
215+ giterr_set (GITERR_CONFIG , "remote '%s' already exists" , name );
216+
217+ return GIT_EEXISTS ;
218+ }
219+
220+ int git_remote_create_init_options (git_remote_create_options * opts , unsigned int version )
221+ {
222+ GIT_INIT_STRUCTURE_FROM_TEMPLATE (
223+ opts , version , git_remote_create_options , GIT_REMOTE_CREATE_OPTIONS_INIT );
224+ return 0 ;
225+ }
226+
227+ int git_remote_create_with_opts (git_remote * * out , const char * url , const git_remote_create_options * opts )
228+ {
229+ git_remote * remote = NULL ;
195230 git_config * config_ro = NULL , * config_rw ;
196231 git_buf canonical_url = GIT_BUF_INIT ;
197232 git_buf var = GIT_BUF_INIT ;
233+ git_buf specbuf = GIT_BUF_INIT ;
234+ const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT ;
198235 int error = -1 ;
199236
200- /* repo, name, and fetch are optional */
201237 assert (out && url );
202238
203- if (repo && (error = git_repository_config_snapshot (& config_ro , repo )) < 0 )
204- return error ;
239+ if (!opts ) {
240+ opts = & dummy_opts ;
241+ }
242+
243+ GITERR_CHECK_VERSION (opts , GIT_REMOTE_CREATE_OPTIONS_VERSION , "git_remote_create_options" );
244+
245+ if (opts -> name != NULL ) {
246+ if ((error = ensure_remote_name_is_valid (opts -> name )) < 0 )
247+ return error ;
248+
249+ if (opts -> repository &&
250+ (error = ensure_remote_doesnot_exist (opts -> repository , opts -> name )) < 0 )
251+ return error ;
252+ }
253+
254+ if (opts -> repository ) {
255+ if ((error = git_repository_config_snapshot (& config_ro , opts -> repository )) < 0 )
256+ goto on_error ;
257+ }
205258
206259 remote = git__calloc (1 , sizeof (git_remote ));
207260 GITERR_CHECK_ALLOC (remote );
208261
209- remote -> repo = repo ;
262+ remote -> repo = opts -> repository ;
210263
211- if ((error = git_vector_init (& remote -> refs , 32 , NULL )) < 0 ||
264+ if ((error = git_vector_init (& remote -> refs , 8 , NULL )) < 0 ||
212265 (error = canonicalize_url (& canonical_url , url )) < 0 )
213266 goto on_error ;
214267
215- if (repo ) {
268+ if (opts -> repository && !( opts -> flags & GIT_REMOTE_CREATE_SKIP_INSTEADOF ) ) {
216269 remote -> url = apply_insteadof (config_ro , canonical_url .ptr , GIT_DIRECTION_FETCH );
217270 } else {
218271 remote -> url = git__strdup (canonical_url .ptr );
219272 }
220273 GITERR_CHECK_ALLOC (remote -> url );
221274
222- if (name != NULL ) {
223- remote -> name = git__strdup (name );
275+ if (opts -> name != NULL ) {
276+ remote -> name = git__strdup (opts -> name );
224277 GITERR_CHECK_ALLOC (remote -> name );
225278
226- if ((error = git_buf_printf (& var , CONFIG_URL_FMT , name )) < 0 )
227- goto on_error ;
228-
229- if (repo &&
230- ((error = git_repository_config__weakptr (& config_rw , repo )) < 0 ||
231- (error = git_config_set_string (config_rw , var .ptr , canonical_url .ptr )) < 0 ))
279+ if (opts -> repository &&
280+ ((error = git_buf_printf (& var , CONFIG_URL_FMT , opts -> name )) < 0 ||
281+ (error = git_repository_config__weakptr (& config_rw , opts -> repository )) < 0 ||
282+ (error = git_config_set_string (config_rw , var .ptr , canonical_url .ptr )) < 0 ))
232283 goto on_error ;
233284 }
234285
235- if (fetch != NULL ) {
236- if ((error = add_refspec (remote , fetch , true)) < 0 )
237- goto on_error ;
286+ if (opts -> fetchspec != NULL ||
287+ (opts -> name && !(opts -> flags & GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC ))) {
288+ const char * fetch = NULL ;
289+ if (opts -> fetchspec ) {
290+ fetch = opts -> fetchspec ;
291+ } else {
292+ if ((error = default_fetchspec_for_name (& specbuf , opts -> name )) < 0 )
293+ goto on_error ;
294+
295+ fetch = git_buf_cstr (& specbuf );
296+ }
238297
239- /* only write for non-anonymous remotes */
240- if (repo && name && (error = write_add_refspec (repo , name , fetch , true)) < 0 )
298+ if ((error = add_refspec (remote , fetch , true)) < 0 )
241299 goto on_error ;
242300
243- if (repo && (error = lookup_remote_prune_config (remote , config_ro , name )) < 0 )
301+ /* only write for named remotes with a repository */
302+ if (opts -> repository && opts -> name &&
303+ ((error = write_add_refspec (opts -> repository , opts -> name , fetch , true)) < 0 ||
304+ (error = lookup_remote_prune_config (remote , config_ro , opts -> name )) < 0 ))
244305 goto on_error ;
245306
246307 /* Move the data over to where the matching functions can find them */
@@ -249,7 +310,7 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
249310 }
250311
251312 /* A remote without a name doesn't download tags */
252- if (!name )
313+ if (!opts -> name )
253314 remote -> download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE ;
254315 else
255316 remote -> download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO ;
@@ -265,79 +326,65 @@ static int create_internal(git_remote **out, git_repository *repo, const char *n
265326 git_remote_free (remote );
266327
267328 git_config_free (config_ro );
329+ git_buf_dispose (& specbuf );
268330 git_buf_dispose (& canonical_url );
269331 git_buf_dispose (& var );
270332 return error ;
271333}
272334
273- static int ensure_remote_doesnot_exist ( git_repository * repo , const char * name )
335+ int git_remote_create ( git_remote * * out , git_repository * repo , const char * name , const char * url )
274336{
337+ git_buf buf = GIT_BUF_INIT ;
275338 int error ;
276- git_remote * remote ;
339+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT ;
277340
278- error = git_remote_lookup (& remote , repo , name );
279-
280- if (error == GIT_ENOTFOUND )
281- return 0 ;
282-
283- if (error < 0 )
341+ /* Those 2 tests are duplicated here because of backward-compatibility */
342+ if ((error = ensure_remote_name_is_valid (name )) < 0 )
284343 return error ;
285344
286- git_remote_free (remote );
287-
288- giterr_set (
289- GITERR_CONFIG ,
290- "remote '%s' already exists" , name );
291-
292- return GIT_EEXISTS ;
293- }
345+ if (canonicalize_url (& buf , url ) < 0 )
346+ return GIT_ERROR ;
294347
348+ git_buf_clear (& buf );
295349
296- int git_remote_create (git_remote * * out , git_repository * repo , const char * name , const char * url )
297- {
298- git_buf buf = GIT_BUF_INIT ;
299- int error ;
350+ opts .repository = repo ;
351+ opts .name = name ;
300352
301- if (git_buf_printf (& buf , "+refs/heads/*:refs/remotes/%s/*" , name ) < 0 )
302- return -1 ;
353+ error = git_remote_create_with_opts (out , url , & opts );
303354
304- error = git_remote_create_with_fetchspec (out , repo , name , url , git_buf_cstr (& buf ));
305355 git_buf_dispose (& buf );
306356
307357 return error ;
308358}
309359
310360int git_remote_create_with_fetchspec (git_remote * * out , git_repository * repo , const char * name , const char * url , const char * fetch )
311361{
312- git_remote * remote = NULL ;
313362 int error ;
363+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT ;
314364
315365 if ((error = ensure_remote_name_is_valid (name )) < 0 )
316366 return error ;
317367
318- if ((error = ensure_remote_doesnot_exist (repo , name )) < 0 )
319- return error ;
368+ opts .repository = repo ;
369+ opts .name = name ;
370+ opts .fetchspec = fetch ;
371+ opts .flags = GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC ;
320372
321- if (create_internal (& remote , repo , name , url , fetch ) < 0 )
322- goto on_error ;
323-
324- * out = remote ;
325-
326- return 0 ;
327-
328- on_error :
329- git_remote_free (remote );
330- return -1 ;
373+ return git_remote_create_with_opts (out , url , & opts );
331374}
332375
333376int git_remote_create_anonymous (git_remote * * out , git_repository * repo , const char * url )
334377{
335- return create_internal (out , repo , NULL , url , NULL );
378+ git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT ;
379+
380+ opts .repository = repo ;
381+
382+ return git_remote_create_with_opts (out , url , & opts );
336383}
337384
338385int git_remote_create_detached (git_remote * * out , const char * url )
339386{
340- return create_internal (out , NULL , NULL , url , NULL );
387+ return git_remote_create_with_opts (out , url , NULL );
341388}
342389
343390int git_remote_dup (git_remote * * dest , git_remote * source )
@@ -1946,8 +1993,7 @@ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const
19461993 if ((error = git_vector_init (problems , 1 , NULL )) < 0 )
19471994 return error ;
19481995
1949- if ((error = git_buf_printf (
1950- & base , "+refs/heads/*:refs/remotes/%s/*" , remote -> name )) < 0 )
1996+ if ((error = default_fetchspec_for_name (& base , remote -> name )) < 0 )
19511997 return error ;
19521998
19531999 git_vector_foreach (& remote -> refspecs , i , spec ) {
@@ -1972,8 +2018,7 @@ static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const
19722018 git_buf_clear (& val );
19732019 git_buf_clear (& var );
19742020
1975- if (git_buf_printf (
1976- & val , "+refs/heads/*:refs/remotes/%s/*" , new_name ) < 0 ||
2021+ if (default_fetchspec_for_name (& val , new_name ) < 0 ||
19772022 git_buf_printf (& var , "remote.%s.fetch" , new_name ) < 0 )
19782023 {
19792024 error = -1 ;
0 commit comments