]> git.proxmox.com Git - libgit2.git/blame - src/branch.c
Fix compilation warning
[libgit2.git] / src / branch.c
CommitLineData
731df570 1/*
2 * Copyright (C) 2009-2012 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 "common.h"
9#include "commit.h"
731df570 10#include "tag.h"
fb910281 11#include "config.h"
12#include "refspec.h"
731df570 13
326ca710 14#include "git2/branch.h"
15
731df570 16static int retrieve_branch_reference(
17 git_reference **branch_reference_out,
18 git_repository *repo,
19 const char *branch_name,
20 int is_remote)
21{
22 git_reference *branch;
23 int error = -1;
24 char *prefix;
25 git_buf ref_name = GIT_BUF_INIT;
26
27 *branch_reference_out = NULL;
28
29 prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR;
30
31 if (git_buf_joinpath(&ref_name, prefix, branch_name) < 0)
32 goto cleanup;
33
34 if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0) {
35 giterr_set(GITERR_REFERENCE,
36 "Cannot locate %s branch '%s'.", is_remote ? "remote-tracking" : "local", branch_name);
37 goto cleanup;
38 }
39
40 *branch_reference_out = branch;
41
42cleanup:
43 git_buf_free(&ref_name);
44 return error;
45}
46
47static int create_error_invalid(const char *msg)
48{
49 giterr_set(GITERR_INVALID, "Cannot create branch - %s", msg);
50 return -1;
51}
52
1c947daa
VM
53static int not_a_local_branch(git_reference *ref)
54{
55 giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref));
56 return -1;
57}
58
731df570 59int git_branch_create(
b308c11e 60 git_reference **ref_out,
f0244463 61 git_repository *repository,
731df570 62 const char *branch_name,
63 const git_object *target,
64 int force)
65{
731df570 66 git_object *commit = NULL;
67 git_reference *branch = NULL;
68 git_buf canonical_branch_name = GIT_BUF_INIT;
69 int error = -1;
70
b308c11e 71 assert(branch_name && target && ref_out);
f0244463 72 assert(git_object_owner(target) == repository);
731df570 73
d1445b75 74 if (git_object_peel(&commit, (git_object *)target, GIT_OBJ_COMMIT) < 0)
75 return create_error_invalid("The given target does not resolve to a commit");
731df570 76
77 if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
78 goto cleanup;
79
62993b61 80 error = git_reference_create_oid(&branch, repository,
81 git_buf_cstr(&canonical_branch_name), git_object_id(commit), force);
731df570 82
62993b61 83 if (!error)
84 *ref_out = branch;
731df570 85
86cleanup:
d1445b75 87 git_object_free(commit);
731df570 88 git_buf_free(&canonical_branch_name);
89 return error;
90}
91
1c947daa 92int git_branch_delete(git_reference *branch)
731df570 93{
4ba23be1 94 int is_head;
aba70781 95 git_buf config_section = GIT_BUF_INIT;
96 int error = -1;
731df570 97
1c947daa 98 assert(branch);
731df570 99
1c947daa
VM
100 if (!git_reference_is_branch(branch) &&
101 !git_reference_is_remote(branch)) {
102 giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch));
103 return -1;
104 }
731df570 105
4ba23be1 106 if ((is_head = git_branch_is_head(branch)) < 0)
107 return is_head;
731df570 108
4ba23be1 109 if (is_head) {
110 giterr_set(GITERR_REFERENCE,
111 "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch));
112 return -1;
731df570 113 }
114
aba70781 115 if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
116 goto on_error;
117
118 if (git_config_rename_section(
0b98a8a4 119 git_reference_owner(branch),
aba70781 120 git_buf_cstr(&config_section),
383f164a 121 NULL) < 0)
0b98a8a4 122 goto on_error;
123
aba70781 124 if (git_reference_delete(branch) < 0)
125 goto on_error;
126
127 error = 0;
128
129on_error:
130 git_buf_free(&config_section);
131 return error;
731df570 132}
133
a8fd805e 134typedef struct {
135 int (*branch_cb)(
136 const char *branch_name,
137 git_branch_t branch_type,
138 void *payload);
139 void *callback_payload;
140 unsigned int branch_type;
141} branch_foreach_filter;
142
143static int branch_foreach_cb(const char *branch_name, void *payload)
144{
145 branch_foreach_filter *filter = (branch_foreach_filter *)payload;
146
147 if (filter->branch_type & GIT_BRANCH_LOCAL &&
148 git__prefixcmp(branch_name, GIT_REFS_HEADS_DIR) == 0)
149 return filter->branch_cb(branch_name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, filter->callback_payload);
150
151 if (filter->branch_type & GIT_BRANCH_REMOTE &&
152 git__prefixcmp(branch_name, GIT_REFS_REMOTES_DIR) == 0)
153 return filter->branch_cb(branch_name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, filter->callback_payload);
154
155 return 0;
156}
157
158int git_branch_foreach(
159 git_repository *repo,
160 unsigned int list_flags,
161 int (*branch_cb)(
162 const char *branch_name,
163 git_branch_t branch_type,
164 void *payload),
165 void *payload
166)
167{
168 branch_foreach_filter filter;
169
170 filter.branch_cb = branch_cb;
171 filter.branch_type = list_flags;
172 filter.callback_payload = payload;
173
174 return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter);
175}
176
bf9e8cc8 177int git_branch_move(
178 git_reference *branch,
179 const char *new_branch_name,
180 int force)
181{
383f164a 182 git_buf new_reference_name = GIT_BUF_INIT,
aba70781 183 old_config_section = GIT_BUF_INIT,
184 new_config_section = GIT_BUF_INIT;
bf9e8cc8 185 int error;
6a8bcfa4 186
bf9e8cc8 187 assert(branch && new_branch_name);
188
189 if (!git_reference_is_branch(branch))
190 return not_a_local_branch(branch);
4615f0f7 191
6a625435
CMN
192 if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
193 goto cleanup;
4615f0f7 194
aba70781 195 if (git_buf_printf(
196 &old_config_section,
197 "branch.%s",
198 git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
199 goto cleanup;
383f164a 200
201 if ((error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force)) < 0)
202 goto cleanup;
203
aba70781 204 if (git_buf_printf(&new_config_section, "branch.%s", new_branch_name) < 0)
205 goto cleanup;
206
207 if ((error = git_config_rename_section(
383f164a 208 git_reference_owner(branch),
aba70781 209 git_buf_cstr(&old_config_section),
210 git_buf_cstr(&new_config_section))) < 0)
383f164a 211 goto cleanup;
4615f0f7 212
6a625435 213cleanup:
6a8bcfa4 214 git_buf_free(&new_reference_name);
aba70781 215 git_buf_free(&old_config_section);
216 git_buf_free(&new_config_section);
6a8bcfa4 217
6a625435 218 return error;
4615f0f7 219}
eed378b6 220
221int git_branch_lookup(
222 git_reference **ref_out,
223 git_repository *repo,
224 const char *branch_name,
225 git_branch_t branch_type)
226{
227 assert(ref_out && repo && branch_name);
228
229 return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE);
230}
fb910281 231
f0244463
VM
232static int retrieve_tracking_configuration(
233 const char **out, git_reference *branch, const char *format)
fb910281 234{
235 git_config *config;
236 git_buf buf = GIT_BUF_INIT;
237 int error;
238
239 if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0)
240 return -1;
241
242 if (git_buf_printf(&buf, format,
243 git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
244 return -1;
245
246 error = git_config_get_string(out, config, git_buf_cstr(&buf));
247 git_buf_free(&buf);
248 return error;
249}
250
251int git_branch_tracking(
252 git_reference **tracking_out,
253 git_reference *branch)
254{
255 const char *remote_name, *merge_name;
256 git_buf buf = GIT_BUF_INIT;
257 int error = -1;
258 git_remote *remote = NULL;
259 const git_refspec *refspec;
260
261 assert(tracking_out && branch);
262
263 if (!git_reference_is_branch(branch))
264 return not_a_local_branch(branch);
265
266 if ((error = retrieve_tracking_configuration(&remote_name, branch, "branch.%s.remote")) < 0)
267 goto cleanup;
268
269 if ((error = retrieve_tracking_configuration(&merge_name, branch, "branch.%s.merge")) < 0)
270 goto cleanup;
b0f6e45d
ET
271
272 if (remote_name == NULL || merge_name == NULL) {
273 error = GIT_ENOTFOUND;
274 goto cleanup;
275 }
fb910281 276
277 if (strcmp(".", remote_name) != 0) {
278 if ((error = git_remote_load(&remote, git_reference_owner(branch), remote_name)) < 0)
279 goto cleanup;
280
281 refspec = git_remote_fetchspec(remote);
e16fc07f 282 if (refspec == NULL
283 || refspec->src == NULL
284 || refspec->dst == NULL) {
285 error = GIT_ENOTFOUND;
286 goto cleanup;
fb910281 287 }
288
289 if (git_refspec_transform_r(&buf, refspec, merge_name) < 0)
290 goto cleanup;
291 } else
292 if (git_buf_sets(&buf, merge_name) < 0)
293 goto cleanup;
294
295 error = git_reference_lookup(
296 tracking_out,
297 git_reference_owner(branch),
298 git_buf_cstr(&buf));
299
300cleanup:
301 git_remote_free(remote);
302 git_buf_free(&buf);
303 return error;
304}
0c78f685 305
306int git_branch_is_head(
307 git_reference *branch)
308{
309 git_reference *head;
310 bool is_same = false;
0532e7bb 311 int error;
0c78f685 312
313 assert(branch);
314
315 if (!git_reference_is_branch(branch))
316 return false;
317
0532e7bb 318 error = git_repository_head(&head, git_reference_owner(branch));
319
8b05bea8 320 if (error == GIT_EORPHANEDHEAD)
0532e7bb 321 return false;
322
323 if (error < 0)
0c78f685 324 return -1;
325
326 is_same = strcmp(
327 git_reference_name(branch),
328 git_reference_name(head)) == 0;
329
330 git_reference_free(head);
331
332 return is_same;
333}