]> git.proxmox.com Git - libgit2.git/blame - src/clone.c
Make sure error messages get set
[libgit2.git] / src / clone.c
CommitLineData
764df57e 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
764df57e
BS
3 *
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.
6 */
7
8#include <assert.h>
830388a7 9
764df57e
BS
10#include "git2/clone.h"
11#include "git2/remote.h"
bb1f6087 12#include "git2/revparse.h"
4fbc899a
BS
13#include "git2/branch.h"
14#include "git2/config.h"
14741d62 15#include "git2/checkout.h"
2b63db4c
BS
16#include "git2/commit.h"
17#include "git2/tree.h"
764df57e
BS
18
19#include "common.h"
20#include "remote.h"
21#include "fileops.h"
4fbc899a 22#include "refs.h"
c3b5099f 23#include "path.h"
764df57e 24
bf0e62a2 25static int create_branch(
7eca3c56 26 git_reference **branch,
27 git_repository *repo,
28 const git_oid *target,
29 const char *name)
4fbc899a 30{
cfbe4be3 31 git_commit *head_obj = NULL;
132c2db6 32 git_reference *branch_ref = NULL;
bf0e62a2 33 int error;
ea817863
BS
34
35 /* Find the target commit */
cfbe4be3 36 if ((error = git_commit_lookup(&head_obj, repo, target)) < 0)
bf0e62a2 37 return error;
ea817863
BS
38
39 /* Create the new branch */
bf0e62a2 40 error = git_branch_create(&branch_ref, repo, name, head_obj, 0);
ea817863 41
cfbe4be3 42 git_commit_free(head_obj);
7eca3c56 43
bf0e62a2 44 if (!error)
7eca3c56 45 *branch = branch_ref;
46 else
47 git_reference_free(branch_ref);
48
bf0e62a2 49 return error;
50}
51
52static int setup_tracking_config(
53 git_repository *repo,
54 const char *branch_name,
55 const char *remote_name,
56 const char *merge_target)
57{
58 git_config *cfg;
59 git_buf remote_key = GIT_BUF_INIT, merge_key = GIT_BUF_INIT;
60 int error = -1;
61
62 if (git_repository_config__weakptr(&cfg, repo) < 0)
63 return -1;
64
65 if (git_buf_printf(&remote_key, "branch.%s.remote", branch_name) < 0)
66 goto cleanup;
67
68 if (git_buf_printf(&merge_key, "branch.%s.merge", branch_name) < 0)
69 goto cleanup;
70
71 if (git_config_set_string(cfg, git_buf_cstr(&remote_key), remote_name) < 0)
72 goto cleanup;
73
74 if (git_config_set_string(cfg, git_buf_cstr(&merge_key), merge_target) < 0)
75 goto cleanup;
76
77 error = 0;
78
79cleanup:
80 git_buf_free(&remote_key);
81 git_buf_free(&merge_key);
82 return error;
83}
84
85static int create_tracking_branch(
86 git_reference **branch,
87 git_repository *repo,
88 const git_oid *target,
89 const char *branch_name)
90{
91 int error;
92
93 if ((error = create_branch(branch, repo, target, branch_name)) < 0)
94 return error;
95
96 return setup_tracking_config(
97 repo,
98 branch_name,
99 GIT_REMOTE_ORIGIN,
100 git_reference_name(*branch));
4fbc899a
BS
101}
102
70edc1b0 103struct head_info {
104 git_repository *repo;
105 git_oid remote_head_oid;
106 git_buf branchname;
d280c71b 107 const git_refspec *refspec;
2ba6f3c7 108 bool found;
70edc1b0 109};
110
d280c71b 111static int reference_matches_remote_head(
112 const char *reference_name,
113 void *payload)
4fbc899a 114{
70edc1b0 115 struct head_info *head_info = (struct head_info *)payload;
ea817863
BS
116 git_oid oid;
117
d280c71b 118 /* TODO: Should we guard against references
119 * which name doesn't start with refs/heads/ ?
120 */
121
ea817863 122 /* Stop looking if we've already found a match */
2ba6f3c7 123 if (head_info->found)
d280c71b 124 return 0;
125
2508cc66 126 if (git_reference_name_to_id(
d280c71b 127 &oid,
128 head_info->repo,
129 reference_name) < 0) {
2ba6f3c7
SC
130 /* If the reference doesn't exists, it obviously cannot match the expected oid. */
131 giterr_clear();
132 return 0;
d280c71b 133 }
ea817863 134
b7f167da 135 if (git_oid__cmp(&head_info->remote_head_oid, &oid) == 0) {
d280c71b 136 /* Determine the local reference name from the remote tracking one */
137 if (git_refspec_transform_l(
b7f167da 138 &head_info->branchname,
d280c71b 139 head_info->refspec,
140 reference_name) < 0)
141 return -1;
b7f167da 142
2ba6f3c7
SC
143 if (git_buf_len(&head_info->branchname) > 0) {
144 if (git_buf_sets(
145 &head_info->branchname,
146 git_buf_cstr(&head_info->branchname) + strlen(GIT_REFS_HEADS_DIR)) < 0)
147 return -1;
148
149 head_info->found = 1;
150 }
ea817863 151 }
d280c71b 152
ea817863 153 return 0;
8340dd5d
BS
154}
155
bf0e62a2 156static int update_head_to_new_branch(
157 git_repository *repo,
158 const git_oid *target,
159 const char *name)
af58ec9e 160{
aa4437f6 161 git_reference *tracking_branch = NULL;
7eca3c56 162 int error;
ea817863 163
bf0e62a2 164 if ((error = create_tracking_branch(
165 &tracking_branch,
166 repo,
167 target,
168 name)) < 0)
169 return error;
ea817863 170
7eca3c56 171 error = git_repository_set_head(repo, git_reference_name(tracking_branch));
172
173 git_reference_free(tracking_branch);
174
175 return error;
af58ec9e
BS
176}
177
41fb1ca0
PK
178static int get_head_callback(git_remote_head *head, void *payload)
179{
180 git_remote_head **destination = (git_remote_head **)payload;
181
182 /* Save the first entry, and terminate the enumeration */
183 *destination = head;
184 return 1;
185}
186
8340dd5d
BS
187static int update_head_to_remote(git_repository *repo, git_remote *remote)
188{
d280c71b 189 int retcode = -1;
4330ab26 190 git_refspec dummy_spec;
ea817863 191 git_remote_head *remote_head;
70edc1b0 192 struct head_info head_info;
d280c71b 193 git_buf remote_master_name = GIT_BUF_INIT;
ea817863 194
bf0e62a2 195 /* Did we just clone an empty repository? */
196 if (remote->refs.length == 0) {
197 return setup_tracking_config(
198 repo,
199 "master",
200 GIT_REMOTE_ORIGIN,
201 GIT_REFS_HEADS_MASTER_FILE);
202 }
203
ea817863 204 /* Get the remote's HEAD. This is always the first ref in remote->refs. */
41fb1ca0
PK
205 remote_head = NULL;
206
207 if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head))
208 return -1;
209
210 assert(remote_head);
211
ea817863
BS
212 git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid);
213 git_buf_init(&head_info.branchname, 16);
214 head_info.repo = repo;
4330ab26 215 head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE);
2ba6f3c7 216 head_info.found = 0;
4330ab26
CMN
217
218 if (head_info.refspec == NULL) {
219 memset(&dummy_spec, 0, sizeof(git_refspec));
220 head_info.refspec = &dummy_spec;
221 }
d280c71b 222
223 /* Determine the remote tracking reference name from the local master */
224 if (git_refspec_transform_r(
225 &remote_master_name,
226 head_info.refspec,
227 GIT_REFS_HEADS_MASTER_FILE) < 0)
228 return -1;
229
230 /* Check to see if the remote HEAD points to the remote master */
231 if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0)
232 goto cleanup;
233
2ba6f3c7 234 if (head_info.found) {
d280c71b 235 retcode = update_head_to_new_branch(
236 repo,
237 &head_info.remote_head_oid,
238 git_buf_cstr(&head_info.branchname));
239
240 goto cleanup;
ea817863 241 }
d280c71b 242
ea817863 243 /* Not master. Check all the other refs. */
d280c71b 244 if (git_reference_foreach(
245 repo,
246 GIT_REF_LISTALL,
247 reference_matches_remote_head,
248 &head_info) < 0)
249 goto cleanup;
250
2ba6f3c7 251 if (head_info.found) {
d280c71b 252 retcode = update_head_to_new_branch(
253 repo,
254 &head_info.remote_head_oid,
255 git_buf_cstr(&head_info.branchname));
256
257 goto cleanup;
258 } else {
28c3beaa
FL
259 retcode = git_repository_set_head_detached(
260 repo,
261 &head_info.remote_head_oid);
262 goto cleanup;
ea817863
BS
263 }
264
d280c71b 265cleanup:
266 git_buf_free(&remote_master_name);
ea817863
BS
267 git_buf_free(&head_info.branchname);
268 return retcode;
bb1f6087
BS
269}
270
88aef766
SC
271static int update_head_to_branch(
272 git_repository *repo,
273 const git_clone_options *options)
274{
275 int retcode;
276 git_buf remote_branch_name = GIT_BUF_INIT;
277 git_reference* remote_ref = NULL;
278
279 assert(options->checkout_branch);
280
281 if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s",
282 options->remote_name, options->checkout_branch)) < 0 )
283 goto cleanup;
284
285 if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
286 goto cleanup;
287
288 retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref),
289 options->checkout_branch);
290
291cleanup:
292 git_reference_free(remote_ref);
1265b51f 293 git_buf_free(&remote_branch_name);
88aef766
SC
294 return retcode;
295}
296
764df57e
BS
297/*
298 * submodules?
764df57e
BS
299 */
300
b412d563
BS
301static int create_and_configure_origin(
302 git_remote **out,
303 git_repository *repo,
304 const char *url,
305 const git_clone_options *options)
306{
307 int error;
00998a12 308 git_remote *origin = NULL;
b412d563 309
29f27599 310 if ((error = git_remote_create(&origin, repo, options->remote_name, url)) < 0)
b412d563
BS
311 goto on_error;
312
313 git_remote_set_cred_acquire_cb(origin, options->cred_acquire_cb,
314 options->cred_acquire_payload);
315 git_remote_set_autotag(origin, options->remote_autotag);
316 /*
317 * Don't write FETCH_HEAD, we'll check out the remote tracking
318 * branch ourselves based on the server's default.
319 */
320 git_remote_set_update_fetchhead(origin, 0);
321
322 if (options->remote_callbacks &&
323 (error = git_remote_set_callbacks(origin, options->remote_callbacks)) < 0)
324 goto on_error;
325
bd0a07f4
BS
326 if (options->fetch_spec) {
327 git_remote_clear_refspecs(origin);
328 if ((error = git_remote_add_fetch(origin, options->fetch_spec)) < 0)
329 goto on_error;
330 }
b412d563
BS
331
332 if (options->push_spec &&
bc6374ea 333 (error = git_remote_add_push(origin, options->push_spec)) < 0)
b412d563
BS
334 goto on_error;
335
336 if (options->pushurl &&
337 (error = git_remote_set_pushurl(origin, options->pushurl)) < 0)
338 goto on_error;
339
621b50e4
BS
340 if ((error = git_remote_save(origin)) < 0)
341 goto on_error;
342
b412d563
BS
343 *out = origin;
344 return 0;
345
346on_error:
00998a12 347 git_remote_free(origin);
b412d563
BS
348 return error;
349}
bb1f6087
BS
350
351
aa1e8674
BS
352static int setup_remotes_and_fetch(
353 git_repository *repo,
b412d563
BS
354 const char *url,
355 const git_clone_options *options)
764df57e 356{
ea817863 357 int retcode = GIT_ERROR;
b412d563 358 git_remote *origin;
ea817863 359
b412d563
BS
360 /* Construct an origin remote */
361 if (!create_and_configure_origin(&origin, repo, url, options)) {
b0f6e45d
ET
362 git_remote_set_update_fetchhead(origin, 0);
363
ea817863 364 /* Connect and download everything */
df705148 365 if (!git_remote_connect(origin, GIT_DIRECTION_FETCH)) {
fe95ac1b
BS
366 if (!(retcode = git_remote_download(origin, options->fetch_progress_cb,
367 options->fetch_progress_payload))) {
ea817863 368 /* Create "origin/foo" branches for all remote branches */
7affe23d 369 if (!git_remote_update_tips(origin)) {
88aef766
SC
370 /* Point HEAD to the requested branch */
371 if (options->checkout_branch) {
372 if (!update_head_to_branch(repo, options))
373 retcode = 0;
374 }
ea817863 375 /* Point HEAD to the same ref as the remote's head */
88aef766 376 else if (!update_head_to_remote(repo, origin)) {
ea817863
BS
377 retcode = 0;
378 }
379 }
380 }
381 git_remote_disconnect(origin);
382 }
d1aee477 383 git_remote_free(origin);
ea817863
BS
384 }
385
386 return retcode;
764df57e
BS
387}
388
acdd3d95 389
4d968f13 390static bool should_checkout(
391 git_repository *repo,
392 bool is_bare,
393 git_checkout_opts *opts)
394{
395 if (is_bare)
396 return false;
397
398 if (!opts)
399 return false;
400
2850252a 401 if (opts->checkout_strategy == GIT_CHECKOUT_NONE)
730df6d0
BS
402 return false;
403
4d968f13 404 return !git_repository_head_orphan(repo);
405}
acdd3d95 406
b412d563
BS
407static void normalize_options(git_clone_options *dst, const git_clone_options *src)
408{
409 git_clone_options default_options = GIT_CLONE_OPTIONS_INIT;
410 if (!src) src = &default_options;
411
412 *dst = *src;
413
414 /* Provide defaults for null pointers */
415 if (!dst->remote_name) dst->remote_name = "origin";
f393d4e8 416 if (!dst->remote_autotag) dst->remote_autotag = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
b412d563
BS
417}
418
419int git_clone(
bf0e62a2 420 git_repository **out,
b412d563
BS
421 const char *url,
422 const char *local_path,
423 const git_clone_options *options)
764df57e 424{
ea817863
BS
425 int retcode = GIT_ERROR;
426 git_repository *repo = NULL;
b412d563 427 git_clone_options normOptions;
926acbcf 428 int remove_directory_on_failure = 0;
b412d563
BS
429
430 assert(out && url && local_path);
ea817863 431
b412d563
BS
432 normalize_options(&normOptions, options);
433 GITERR_CHECK_VERSION(&normOptions, GIT_CLONE_OPTIONS_VERSION, "git_clone_options");
434
f6f48f90
RB
435 /* Only clone to a new directory or an empty directory */
436 if (git_path_exists(local_path) && !git_path_is_empty_dir(local_path)) {
437 giterr_set(GITERR_INVALID,
438 "'%s' exists and is not an empty directory", path);
ea817863
BS
439 return GIT_ERROR;
440 }
441
926acbcf
JM
442 /* Only remove the directory on failure if we create it */
443 remove_directory_on_failure = !git_path_exists(local_path);
444
b412d563
BS
445 if (!(retcode = git_repository_init(&repo, local_path, normOptions.bare))) {
446 if ((retcode = setup_remotes_and_fetch(repo, url, &normOptions)) < 0) {
ea817863
BS
447 /* Failed to fetch; clean up */
448 git_repository_free(repo);
926acbcf
JM
449
450 if (remove_directory_on_failure)
451 git_futils_rmdir_r(local_path, NULL, GIT_RMDIR_REMOVE_FILES);
452 else
453 git_futils_cleanupdir_r(local_path);
454
ea817863
BS
455 } else {
456 *out = repo;
457 retcode = 0;
458 }
459 }
460
730df6d0
BS
461 if (!retcode && should_checkout(repo, normOptions.bare, &normOptions.checkout_opts))
462 retcode = git_checkout_head(*out, &normOptions.checkout_opts);
bf0e62a2 463
ea817863 464 return retcode;
764df57e 465}