2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
10 #include "git2/clone.h"
11 #include "git2/remote.h"
12 #include "git2/revparse.h"
13 #include "git2/branch.h"
14 #include "git2/config.h"
15 #include "git2/checkout.h"
16 #include "git2/commit.h"
17 #include "git2/tree.h"
23 #include "repository.h"
26 static int clone_local_into(git_repository
*repo
, git_remote
*remote
, const git_fetch_options
*fetch_opts
, const git_checkout_options
*co_opts
, const char *branch
, int link
);
28 static int create_branch(
29 git_reference
**branch
,
31 const git_oid
*target
,
33 const char *log_message
)
35 git_commit
*head_obj
= NULL
;
36 git_reference
*branch_ref
= NULL
;
37 git_str refname
= GIT_STR_INIT
;
40 /* Find the target commit */
41 if ((error
= git_commit_lookup(&head_obj
, repo
, target
)) < 0)
44 /* Create the new branch */
45 if ((error
= git_str_printf(&refname
, GIT_REFS_HEADS_DIR
"%s", name
)) < 0)
48 error
= git_reference_create(&branch_ref
, repo
, git_str_cstr(&refname
), target
, 0, log_message
);
49 git_str_dispose(&refname
);
50 git_commit_free(head_obj
);
55 git_reference_free(branch_ref
);
60 static int setup_tracking_config(
62 const char *branch_name
,
63 const char *remote_name
,
64 const char *merge_target
)
67 git_str remote_key
= GIT_STR_INIT
, merge_key
= GIT_STR_INIT
;
70 if (git_repository_config__weakptr(&cfg
, repo
) < 0)
73 if (git_str_printf(&remote_key
, "branch.%s.remote", branch_name
) < 0)
76 if (git_str_printf(&merge_key
, "branch.%s.merge", branch_name
) < 0)
79 if (git_config_set_string(cfg
, git_str_cstr(&remote_key
), remote_name
) < 0)
82 if (git_config_set_string(cfg
, git_str_cstr(&merge_key
), merge_target
) < 0)
88 git_str_dispose(&remote_key
);
89 git_str_dispose(&merge_key
);
93 static int create_tracking_branch(
94 git_reference
**branch
,
96 const git_oid
*target
,
97 const char *branch_name
,
98 const char *log_message
)
102 if ((error
= create_branch(branch
, repo
, target
, branch_name
, log_message
)) < 0)
105 return setup_tracking_config(
109 git_reference_name(*branch
));
112 static int update_head_to_new_branch(
113 git_repository
*repo
,
114 const git_oid
*target
,
116 const char *reflog_message
)
118 git_reference
*tracking_branch
= NULL
;
121 if (!git__prefixcmp(name
, GIT_REFS_HEADS_DIR
))
122 name
+= strlen(GIT_REFS_HEADS_DIR
);
124 error
= create_tracking_branch(&tracking_branch
, repo
, target
, name
,
128 error
= git_repository_set_head(
129 repo
, git_reference_name(tracking_branch
));
131 git_reference_free(tracking_branch
);
133 /* if it already existed, then the user's refspec created it for us, ignore it' */
134 if (error
== GIT_EEXISTS
)
140 static int update_head_to_default(git_repository
*repo
)
142 git_str initialbranch
= GIT_STR_INIT
;
143 const char *branch_name
;
146 if ((error
= git_repository_initialbranch(&initialbranch
, repo
)) < 0)
149 if (git__prefixcmp(initialbranch
.ptr
, GIT_REFS_HEADS_DIR
) != 0) {
150 git_error_set(GIT_ERROR_INVALID
, "invalid initial branch '%s'", initialbranch
.ptr
);
155 branch_name
= initialbranch
.ptr
+ strlen(GIT_REFS_HEADS_DIR
);
157 error
= setup_tracking_config(repo
, branch_name
, GIT_REMOTE_ORIGIN
,
161 git_str_dispose(&initialbranch
);
165 static int update_remote_head(
166 git_repository
*repo
,
169 const char *reflog_message
)
171 git_refspec
*refspec
;
172 git_reference
*remote_head
= NULL
;
173 git_str remote_head_name
= GIT_STR_INIT
;
174 git_str remote_branch_name
= GIT_STR_INIT
;
177 /* Determine the remote tracking ref name from the local branch */
178 refspec
= git_remote__matching_refspec(remote
, git_str_cstr(target
));
180 if (refspec
== NULL
) {
181 git_error_set(GIT_ERROR_NET
, "the remote's default branch does not fit the refspec configuration");
182 error
= GIT_EINVALIDSPEC
;
186 if ((error
= git_refspec__transform(
189 git_str_cstr(target
))) < 0)
192 if ((error
= git_str_printf(&remote_head_name
,
194 GIT_REFS_REMOTES_DIR
,
195 git_remote_name(remote
),
199 error
= git_reference_symbolic_create(
202 git_str_cstr(&remote_head_name
),
203 git_str_cstr(&remote_branch_name
),
208 git_reference_free(remote_head
);
209 git_str_dispose(&remote_branch_name
);
210 git_str_dispose(&remote_head_name
);
214 static int update_head_to_remote(
215 git_repository
*repo
,
217 const char *reflog_message
)
221 const git_remote_head
*remote_head
, **refs
;
222 const git_oid
*remote_head_id
;
223 git_str branch
= GIT_STR_INIT
;
225 if ((error
= git_remote_ls(&refs
, &refs_len
, remote
)) < 0)
228 /* We cloned an empty repository or one with an unborn HEAD */
229 if (refs_len
== 0 || strcmp(refs
[0]->name
, GIT_HEAD_FILE
))
230 return update_head_to_default(repo
);
232 /* We know we have HEAD, let's see where it points */
233 remote_head
= refs
[0];
234 GIT_ASSERT(remote_head
);
236 remote_head_id
= &remote_head
->oid
;
238 error
= git_remote__default_branch(&branch
, remote
);
239 if (error
== GIT_ENOTFOUND
) {
240 error
= git_repository_set_head_detached(
241 repo
, remote_head_id
);
245 if ((error
= update_remote_head(repo
, remote
, &branch
, reflog_message
)) < 0)
248 error
= update_head_to_new_branch(
251 git_str_cstr(&branch
),
255 git_str_dispose(&branch
);
260 static int update_head_to_branch(
261 git_repository
*repo
,
264 const char *reflog_message
)
267 git_str remote_branch_name
= GIT_STR_INIT
;
268 git_reference
*remote_ref
= NULL
;
269 git_str default_branch
= GIT_STR_INIT
;
271 GIT_ASSERT_ARG(remote
);
272 GIT_ASSERT_ARG(branch
);
274 if ((retcode
= git_str_printf(&remote_branch_name
, GIT_REFS_REMOTES_DIR
"%s/%s",
275 git_remote_name(remote
), branch
)) < 0 )
278 if ((retcode
= git_reference_lookup(&remote_ref
, repo
, git_str_cstr(&remote_branch_name
))) < 0)
281 if ((retcode
= update_head_to_new_branch(repo
, git_reference_target(remote_ref
), branch
,
282 reflog_message
)) < 0)
285 if ((retcode
= git_remote__default_branch(&default_branch
, remote
)) < 0)
288 if (!git_remote__matching_refspec(remote
, git_str_cstr(&default_branch
)))
291 retcode
= update_remote_head(repo
, remote
, &default_branch
, reflog_message
);
294 git_reference_free(remote_ref
);
295 git_str_dispose(&remote_branch_name
);
296 git_str_dispose(&default_branch
);
300 static int default_repository_create(git_repository
**out
, const char *path
, int bare
, void *payload
)
304 return git_repository_init(out
, path
, bare
);
307 static int default_remote_create(
309 git_repository
*repo
,
316 return git_remote_create(out
, repo
, name
, url
);
323 static int create_and_configure_origin(
325 git_repository
*repo
,
327 const git_clone_options
*options
)
330 git_remote
*origin
= NULL
;
331 char buf
[GIT_PATH_MAX
];
332 git_remote_create_cb remote_create
= options
->remote_cb
;
333 void *payload
= options
->remote_cb_payload
;
335 /* If the path exists and is a dir, the url should be the absolute path */
336 if (git_fs_path_root(url
) < 0 && git_fs_path_exists(url
) && git_fs_path_isdir(url
)) {
337 if (p_realpath(url
, buf
) == NULL
)
343 if (!remote_create
) {
344 remote_create
= default_remote_create
;
348 if ((error
= remote_create(&origin
, repo
, "origin", url
, payload
)) < 0)
355 git_remote_free(origin
);
359 static bool should_checkout(
360 git_repository
*repo
,
362 const git_checkout_options
*opts
)
370 if (opts
->checkout_strategy
== GIT_CHECKOUT_NONE
)
373 return !git_repository_head_unborn(repo
);
376 static int checkout_branch(git_repository
*repo
, git_remote
*remote
, const git_checkout_options
*co_opts
, const char *branch
, const char *reflog_message
)
381 error
= update_head_to_branch(repo
, remote
, branch
, reflog_message
);
382 /* Point HEAD to the same ref as the remote's head */
384 error
= update_head_to_remote(repo
, remote
, reflog_message
);
386 if (!error
&& should_checkout(repo
, git_repository_is_bare(repo
), co_opts
))
387 error
= git_checkout_head(repo
, co_opts
);
392 static int clone_into(git_repository
*repo
, git_remote
*_remote
, const git_fetch_options
*opts
, const git_checkout_options
*co_opts
, const char *branch
)
395 git_str reflog_message
= GIT_STR_INIT
;
396 git_fetch_options fetch_opts
;
399 GIT_ASSERT_ARG(repo
);
400 GIT_ASSERT_ARG(_remote
);
402 if (!git_repository_is_empty(repo
)) {
403 git_error_set(GIT_ERROR_INVALID
, "the repository is not empty");
407 if ((error
= git_remote_dup(&remote
, _remote
)) < 0)
410 memcpy(&fetch_opts
, opts
, sizeof(git_fetch_options
));
411 fetch_opts
.update_fetchhead
= 0;
412 fetch_opts
.download_tags
= GIT_REMOTE_DOWNLOAD_TAGS_ALL
;
413 git_str_printf(&reflog_message
, "clone: from %s", git_remote_url(remote
));
415 if ((error
= git_remote_fetch(remote
, NULL
, &fetch_opts
, git_str_cstr(&reflog_message
))) != 0)
418 error
= checkout_branch(repo
, remote
, co_opts
, branch
, git_str_cstr(&reflog_message
));
421 git_remote_free(remote
);
422 git_str_dispose(&reflog_message
);
427 int git_clone__should_clone_local(const char *url_or_path
, git_clone_local_t local
)
429 git_str fromurl
= GIT_STR_INIT
;
430 const char *path
= url_or_path
;
431 bool is_url
, is_local
;
433 if (local
== GIT_CLONE_NO_LOCAL
)
436 if ((is_url
= git_fs_path_is_local_file_url(url_or_path
)) != 0) {
437 if (git_fs_path_fromurl(&fromurl
, url_or_path
) < 0) {
445 is_local
= (!is_url
|| local
!= GIT_CLONE_LOCAL_AUTO
) &&
446 git_fs_path_isdir(path
);
449 git_str_dispose(&fromurl
);
453 static int git__clone(
454 git_repository
**out
,
456 const char *local_path
,
457 const git_clone_options
*_options
,
461 git_repository
*repo
= NULL
;
463 git_clone_options options
= GIT_CLONE_OPTIONS_INIT
;
464 uint32_t rmdir_flags
= GIT_RMDIR_REMOVE_FILES
;
465 git_repository_create_cb repository_cb
;
469 GIT_ASSERT_ARG(local_path
);
472 memcpy(&options
, _options
, sizeof(git_clone_options
));
474 GIT_ERROR_CHECK_VERSION(&options
, GIT_CLONE_OPTIONS_VERSION
, "git_clone_options");
476 /* Only clone to a new directory or an empty directory */
477 if (git_fs_path_exists(local_path
) && !use_existing
&& !git_fs_path_is_empty_dir(local_path
)) {
478 git_error_set(GIT_ERROR_INVALID
,
479 "'%s' exists and is not an empty directory", local_path
);
483 /* Only remove the root directory on failure if we create it */
484 if (git_fs_path_exists(local_path
))
485 rmdir_flags
|= GIT_RMDIR_SKIP_ROOT
;
487 if (options
.repository_cb
)
488 repository_cb
= options
.repository_cb
;
490 repository_cb
= default_repository_create
;
492 if ((error
= repository_cb(&repo
, local_path
, options
.bare
, options
.repository_cb_payload
)) < 0)
495 if (!(error
= create_and_configure_origin(&origin
, repo
, url
, &options
))) {
496 int clone_local
= git_clone__should_clone_local(url
, options
.local
);
497 int link
= options
.local
!= GIT_CLONE_LOCAL_NO_LINKS
;
499 if (clone_local
== 1)
500 error
= clone_local_into(
501 repo
, origin
, &options
.fetch_opts
, &options
.checkout_opts
,
502 options
.checkout_branch
, link
);
503 else if (clone_local
== 0)
505 repo
, origin
, &options
.fetch_opts
, &options
.checkout_opts
,
506 options
.checkout_branch
);
510 git_remote_free(origin
);
514 git_error_state last_error
= {0};
515 git_error_state_capture(&last_error
, error
);
517 git_repository_free(repo
);
520 (void)git_futils_rmdir_r(local_path
, NULL
, rmdir_flags
);
522 git_error_state_restore(&last_error
);
530 git_repository
**out
,
532 const char *local_path
,
533 const git_clone_options
*_options
)
535 return git__clone(out
, url
, local_path
, _options
, 0);
538 int git_clone__submodule(
539 git_repository
**out
,
541 const char *local_path
,
542 const git_clone_options
*_options
)
544 return git__clone(out
, url
, local_path
, _options
, 1);
547 int git_clone_options_init(git_clone_options
*opts
, unsigned int version
)
549 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
550 opts
, version
, git_clone_options
, GIT_CLONE_OPTIONS_INIT
);
554 #ifndef GIT_DEPRECATE_HARD
555 int git_clone_init_options(git_clone_options
*opts
, unsigned int version
)
557 return git_clone_options_init(opts
, version
);
561 static bool can_link(const char *src
, const char *dst
, int link
)
570 struct stat st_src
, st_dst
;
575 if (p_stat(src
, &st_src
) < 0)
578 if (p_stat(dst
, &st_dst
) < 0)
581 return st_src
.st_dev
== st_dst
.st_dev
;
585 static int clone_local_into(git_repository
*repo
, git_remote
*remote
, const git_fetch_options
*fetch_opts
, const git_checkout_options
*co_opts
, const char *branch
, int link
)
589 git_str src_odb
= GIT_STR_INIT
, dst_odb
= GIT_STR_INIT
, src_path
= GIT_STR_INIT
;
590 git_str reflog_message
= GIT_STR_INIT
;
592 GIT_ASSERT_ARG(repo
);
593 GIT_ASSERT_ARG(remote
);
595 if (!git_repository_is_empty(repo
)) {
596 git_error_set(GIT_ERROR_INVALID
, "the repository is not empty");
601 * Let's figure out what path we should use for the source
602 * repo, if it's not rooted, the path should be relative to
603 * the repository's worktree/gitdir.
605 if ((error
= git_fs_path_from_url_or_path(&src_path
, git_remote_url(remote
))) < 0)
608 /* Copy .git/objects/ from the source to the target */
609 if ((error
= git_repository_open(&src
, git_str_cstr(&src_path
))) < 0) {
610 git_str_dispose(&src_path
);
614 if (git_repository__item_path(&src_odb
, src
, GIT_REPOSITORY_ITEM_OBJECTS
) < 0 ||
615 git_repository__item_path(&dst_odb
, repo
, GIT_REPOSITORY_ITEM_OBJECTS
) < 0) {
621 if (can_link(git_repository_path(src
), git_repository_path(repo
), link
))
622 flags
|= GIT_CPDIR_LINK_FILES
;
624 error
= git_futils_cp_r(git_str_cstr(&src_odb
), git_str_cstr(&dst_odb
),
625 flags
, GIT_OBJECT_DIR_MODE
);
628 * can_link() doesn't catch all variations, so if we hit an
629 * error and did want to link, let's try again without trying
632 if (error
< 0 && link
) {
633 flags
&= ~GIT_CPDIR_LINK_FILES
;
634 error
= git_futils_cp_r(git_str_cstr(&src_odb
), git_str_cstr(&dst_odb
),
635 flags
, GIT_OBJECT_DIR_MODE
);
641 git_str_printf(&reflog_message
, "clone: from %s", git_remote_url(remote
));
643 if ((error
= git_remote_fetch(remote
, NULL
, fetch_opts
, git_str_cstr(&reflog_message
))) != 0)
646 error
= checkout_branch(repo
, remote
, co_opts
, branch
, git_str_cstr(&reflog_message
));
649 git_str_dispose(&reflog_message
);
650 git_str_dispose(&src_path
);
651 git_str_dispose(&src_odb
);
652 git_str_dispose(&dst_odb
);
653 git_repository_free(src
);