]> git.proxmox.com Git - libgit2.git/blame - src/clone.c
config: allow setting multivars when none exist yet
[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
d280c71b 135 if (git_oid_cmp(&head_info->remote_head_oid, &oid) == 0) {
136 /* Determine the local reference name from the remote tracking one */
137 if (git_refspec_transform_l(
138 &head_info->branchname,
139 head_info->refspec,
140 reference_name) < 0)
141 return -1;
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;
ea817863 190 git_remote_head *remote_head;
70edc1b0 191 struct head_info head_info;
d280c71b 192 git_buf remote_master_name = GIT_BUF_INIT;
ea817863 193
bf0e62a2 194 /* Did we just clone an empty repository? */
195 if (remote->refs.length == 0) {
196 return setup_tracking_config(
197 repo,
198 "master",
199 GIT_REMOTE_ORIGIN,
200 GIT_REFS_HEADS_MASTER_FILE);
201 }
202
ea817863 203 /* Get the remote's HEAD. This is always the first ref in remote->refs. */
41fb1ca0
PK
204 remote_head = NULL;
205
206 if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head))
207 return -1;
208
209 assert(remote_head);
210
ea817863
BS
211 git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid);
212 git_buf_init(&head_info.branchname, 16);
213 head_info.repo = repo;
d280c71b 214 head_info.refspec = git_remote_fetchspec(remote);
2ba6f3c7 215 head_info.found = 0;
d280c71b 216
217 /* Determine the remote tracking reference name from the local master */
218 if (git_refspec_transform_r(
219 &remote_master_name,
220 head_info.refspec,
221 GIT_REFS_HEADS_MASTER_FILE) < 0)
222 return -1;
223
224 /* Check to see if the remote HEAD points to the remote master */
225 if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0)
226 goto cleanup;
227
2ba6f3c7 228 if (head_info.found) {
d280c71b 229 retcode = update_head_to_new_branch(
230 repo,
231 &head_info.remote_head_oid,
232 git_buf_cstr(&head_info.branchname));
233
234 goto cleanup;
ea817863 235 }
d280c71b 236
ea817863 237 /* Not master. Check all the other refs. */
d280c71b 238 if (git_reference_foreach(
239 repo,
240 GIT_REF_LISTALL,
241 reference_matches_remote_head,
242 &head_info) < 0)
243 goto cleanup;
244
2ba6f3c7 245 if (head_info.found) {
d280c71b 246 retcode = update_head_to_new_branch(
247 repo,
248 &head_info.remote_head_oid,
249 git_buf_cstr(&head_info.branchname));
250
251 goto cleanup;
252 } else {
28c3beaa
FL
253 retcode = git_repository_set_head_detached(
254 repo,
255 &head_info.remote_head_oid);
256 goto cleanup;
ea817863
BS
257 }
258
d280c71b 259cleanup:
260 git_buf_free(&remote_master_name);
ea817863
BS
261 git_buf_free(&head_info.branchname);
262 return retcode;
bb1f6087
BS
263}
264
88aef766
SC
265static int update_head_to_branch(
266 git_repository *repo,
267 const git_clone_options *options)
268{
269 int retcode;
270 git_buf remote_branch_name = GIT_BUF_INIT;
271 git_reference* remote_ref = NULL;
272
273 assert(options->checkout_branch);
274
275 if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s",
276 options->remote_name, options->checkout_branch)) < 0 )
277 goto cleanup;
278
279 if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
280 goto cleanup;
281
282 retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref),
283 options->checkout_branch);
284
285cleanup:
286 git_reference_free(remote_ref);
1265b51f 287 git_buf_free(&remote_branch_name);
88aef766
SC
288 return retcode;
289}
290
764df57e
BS
291/*
292 * submodules?
764df57e
BS
293 */
294
b412d563
BS
295static int create_and_configure_origin(
296 git_remote **out,
297 git_repository *repo,
298 const char *url,
299 const git_clone_options *options)
300{
301 int error;
00998a12 302 git_remote *origin = NULL;
b412d563 303
29f27599 304 if ((error = git_remote_create(&origin, repo, options->remote_name, url)) < 0)
b412d563
BS
305 goto on_error;
306
307 git_remote_set_cred_acquire_cb(origin, options->cred_acquire_cb,
308 options->cred_acquire_payload);
309 git_remote_set_autotag(origin, options->remote_autotag);
310 /*
311 * Don't write FETCH_HEAD, we'll check out the remote tracking
312 * branch ourselves based on the server's default.
313 */
314 git_remote_set_update_fetchhead(origin, 0);
315
316 if (options->remote_callbacks &&
317 (error = git_remote_set_callbacks(origin, options->remote_callbacks)) < 0)
318 goto on_error;
319
320 if (options->fetch_spec &&
321 (error = git_remote_set_fetchspec(origin, options->fetch_spec)) < 0)
322 goto on_error;
323
324 if (options->push_spec &&
325 (error = git_remote_set_pushspec(origin, options->push_spec)) < 0)
326 goto on_error;
327
328 if (options->pushurl &&
329 (error = git_remote_set_pushurl(origin, options->pushurl)) < 0)
330 goto on_error;
331
621b50e4
BS
332 if ((error = git_remote_save(origin)) < 0)
333 goto on_error;
334
b412d563
BS
335 *out = origin;
336 return 0;
337
338on_error:
00998a12 339 git_remote_free(origin);
b412d563
BS
340 return error;
341}
bb1f6087
BS
342
343
aa1e8674
BS
344static int setup_remotes_and_fetch(
345 git_repository *repo,
b412d563
BS
346 const char *url,
347 const git_clone_options *options)
764df57e 348{
ea817863 349 int retcode = GIT_ERROR;
b412d563 350 git_remote *origin;
ea817863 351
b412d563
BS
352 /* Construct an origin remote */
353 if (!create_and_configure_origin(&origin, repo, url, options)) {
b0f6e45d
ET
354 git_remote_set_update_fetchhead(origin, 0);
355
ea817863 356 /* Connect and download everything */
df705148 357 if (!git_remote_connect(origin, GIT_DIRECTION_FETCH)) {
fe95ac1b
BS
358 if (!(retcode = git_remote_download(origin, options->fetch_progress_cb,
359 options->fetch_progress_payload))) {
ea817863 360 /* Create "origin/foo" branches for all remote branches */
7affe23d 361 if (!git_remote_update_tips(origin)) {
88aef766
SC
362 /* Point HEAD to the requested branch */
363 if (options->checkout_branch) {
364 if (!update_head_to_branch(repo, options))
365 retcode = 0;
366 }
ea817863 367 /* Point HEAD to the same ref as the remote's head */
88aef766 368 else if (!update_head_to_remote(repo, origin)) {
ea817863
BS
369 retcode = 0;
370 }
371 }
372 }
373 git_remote_disconnect(origin);
374 }
d1aee477 375 git_remote_free(origin);
ea817863
BS
376 }
377
378 return retcode;
764df57e
BS
379}
380
acdd3d95 381
acdd3d95
BS
382static bool path_is_okay(const char *path)
383{
ea817863
BS
384 /* The path must either not exist, or be an empty directory */
385 if (!git_path_exists(path)) return true;
d024419f 386 if (!git_path_is_empty_dir(path)) {
ea817863
BS
387 giterr_set(GITERR_INVALID,
388 "'%s' exists and is not an empty directory", path);
389 return false;
390 }
d024419f 391 return true;
acdd3d95
BS
392}
393
4d968f13 394static bool should_checkout(
395 git_repository *repo,
396 bool is_bare,
397 git_checkout_opts *opts)
398{
399 if (is_bare)
400 return false;
401
402 if (!opts)
403 return false;
404
2850252a 405 if (opts->checkout_strategy == GIT_CHECKOUT_NONE)
730df6d0
BS
406 return false;
407
4d968f13 408 return !git_repository_head_orphan(repo);
409}
acdd3d95 410
b412d563
BS
411static void normalize_options(git_clone_options *dst, const git_clone_options *src)
412{
413 git_clone_options default_options = GIT_CLONE_OPTIONS_INIT;
414 if (!src) src = &default_options;
415
416 *dst = *src;
417
418 /* Provide defaults for null pointers */
419 if (!dst->remote_name) dst->remote_name = "origin";
f393d4e8 420 if (!dst->remote_autotag) dst->remote_autotag = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
b412d563
BS
421}
422
423int git_clone(
bf0e62a2 424 git_repository **out,
b412d563
BS
425 const char *url,
426 const char *local_path,
427 const git_clone_options *options)
764df57e 428{
ea817863
BS
429 int retcode = GIT_ERROR;
430 git_repository *repo = NULL;
b412d563 431 git_clone_options normOptions;
926acbcf 432 int remove_directory_on_failure = 0;
b412d563
BS
433
434 assert(out && url && local_path);
ea817863 435
b412d563
BS
436 normalize_options(&normOptions, options);
437 GITERR_CHECK_VERSION(&normOptions, GIT_CLONE_OPTIONS_VERSION, "git_clone_options");
438
439 if (!path_is_okay(local_path)) {
ea817863
BS
440 return GIT_ERROR;
441 }
442
926acbcf
JM
443 /* Only remove the directory on failure if we create it */
444 remove_directory_on_failure = !git_path_exists(local_path);
445
b412d563
BS
446 if (!(retcode = git_repository_init(&repo, local_path, normOptions.bare))) {
447 if ((retcode = setup_remotes_and_fetch(repo, url, &normOptions)) < 0) {
ea817863
BS
448 /* Failed to fetch; clean up */
449 git_repository_free(repo);
926acbcf
JM
450
451 if (remove_directory_on_failure)
452 git_futils_rmdir_r(local_path, NULL, GIT_RMDIR_REMOVE_FILES);
453 else
454 git_futils_cleanupdir_r(local_path);
455
ea817863
BS
456 } else {
457 *out = repo;
458 retcode = 0;
459 }
460 }
461
730df6d0
BS
462 if (!retcode && should_checkout(repo, normOptions.bare, &normOptions.checkout_opts))
463 retcode = git_checkout_head(*out, &normOptions.checkout_opts);
bf0e62a2 464
ea817863 465 return retcode;
764df57e 466}