]> git.proxmox.com Git - libgit2.git/blob - src/fetch.c
Merge pull request #444 from carlosmn/fetch-fixes
[libgit2.git] / src / fetch.c
1 /*
2 * Copyright (C) 2009-2011 the libgit2 contributors
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 "git2/remote.h"
9 #include "git2/oid.h"
10 #include "git2/refs.h"
11 #include "git2/revwalk.h"
12
13 #include "common.h"
14 #include "transport.h"
15 #include "remote.h"
16 #include "refspec.h"
17 #include "fetch.h"
18
19 static int filter_wants(git_remote *remote)
20 {
21 git_vector list;
22 git_headarray refs;
23 git_transport *t = remote->transport;
24 git_repository *repo = remote->repo;
25 const git_refspec *spec;
26 int error;
27 unsigned int i = 0;
28
29 error = git_vector_init(&list, 16, NULL);
30 if (error < GIT_SUCCESS)
31 return error;
32
33 error = t->ls(t, &refs);
34 if (error < GIT_SUCCESS) {
35 error = git__rethrow(error, "Failed to get remote ref list");
36 goto cleanup;
37 }
38
39 /*
40 * The fetch refspec can be NULL, and what this means is that the
41 * user didn't specify one. This is fine, as it means that we're
42 * not interested in any particular branch but just the remote's
43 * HEAD, which will be stored in FETCH_HEAD after the fetch.
44 */
45 spec = git_remote_fetchspec(remote);
46
47 /*
48 * We need to handle HEAD separately, as we always want it, but it
49 * probably won't matcht he refspec.
50 */
51 head = refs.heads[0];
52 if (refs.len > 0 && !strcmp(head->name, GIT_HEAD_FILE)) {
53 if (git_odb_exists(repo->db, &head->oid))
54 head->local = 1;
55 else
56 remote->need_pack = 1;
57
58 i = 1;
59 error = git_vector_insert(&list, refs.heads[0]);
60 if (error < GIT_SUCCESS)
61 goto cleanup;
62 }
63
64 for (; i < refs.len; ++i) {
65 git_remote_head *head = refs.heads[i];
66
67 /* If it doesn't match the refpec, we don't want it */
68 error = git_refspec_src_match(spec, head->name);
69 if (error == GIT_ENOMATCH)
70 continue;
71 if (error < GIT_SUCCESS) {
72 error = git__rethrow(error, "Error matching remote ref name");
73 goto cleanup;
74 }
75
76 /* If we have the object, mark it so we don't ask for it */
77 if (git_odb_exists(repo->db, &head->oid))
78 head->local = 1;
79 else
80 remote->need_pack = 1;
81
82 error = git_vector_insert(&list, head);
83 if (error < GIT_SUCCESS)
84 goto cleanup;
85 }
86
87 remote->refs.len = list.length;
88 remote->refs.heads = (git_remote_head **) list.contents;
89
90 return GIT_SUCCESS;
91
92 cleanup:
93 git_vector_free(&list);
94 return error;
95 }
96
97 /*
98 * In this first version, we push all our refs in and start sending
99 * them out. When we get an ACK we hide that commit and continue
100 * traversing until we're done
101 */
102 int git_fetch_negotiate(git_remote *remote)
103 {
104 int error;
105 git_headarray *list = &remote->refs;
106 git_transport *t = remote->transport;
107
108 error = filter_wants(remote);
109 if (error < GIT_SUCCESS)
110 return git__rethrow(error, "Failed to filter the reference list for wants");
111
112 /* Don't try to negotiate when we don't want anything */
113 if (list->len == 0)
114 return GIT_SUCCESS;
115 if (!remote->need_pack)
116 return GIT_SUCCESS;
117
118 /*
119 * Now we have everything set up so we can start tell the server
120 * what we want and what we have.
121 */
122 error = t->send_wants(t, list);
123 if (error < GIT_SUCCESS)
124 return git__rethrow(error, "Failed to send want list");
125
126 return t->negotiate_fetch(t, remote->repo, &remote->refs);
127 }
128
129 int git_fetch_download_pack(char **out, git_remote *remote)
130 {
131 if(!remote->need_pack) {
132 *out = NULL;
133 return GIT_SUCCESS;
134 }
135
136 return remote->transport->download_pack(out, remote->transport, remote->repo);
137 }