]>
Commit | Line | Data |
---|---|---|
731df570 | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
731df570 | 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" | |
bf031581 | 13 | #include "refs.h" |
4330ab26 | 14 | #include "remote.h" |
731df570 | 15 | |
326ca710 | 16 | #include "git2/branch.h" |
17 | ||
731df570 | 18 | static int retrieve_branch_reference( |
19 | git_reference **branch_reference_out, | |
20 | git_repository *repo, | |
21 | const char *branch_name, | |
22 | int is_remote) | |
23 | { | |
24 | git_reference *branch; | |
25 | int error = -1; | |
26 | char *prefix; | |
27 | git_buf ref_name = GIT_BUF_INIT; | |
28 | ||
29 | *branch_reference_out = NULL; | |
30 | ||
31 | prefix = is_remote ? GIT_REFS_REMOTES_DIR : GIT_REFS_HEADS_DIR; | |
32 | ||
33 | if (git_buf_joinpath(&ref_name, prefix, branch_name) < 0) | |
34 | goto cleanup; | |
35 | ||
36 | if ((error = git_reference_lookup(&branch, repo, ref_name.ptr)) < 0) { | |
37 | giterr_set(GITERR_REFERENCE, | |
38 | "Cannot locate %s branch '%s'.", is_remote ? "remote-tracking" : "local", branch_name); | |
39 | goto cleanup; | |
40 | } | |
41 | ||
42 | *branch_reference_out = branch; | |
43 | ||
44 | cleanup: | |
45 | git_buf_free(&ref_name); | |
46 | return error; | |
47 | } | |
48 | ||
bf031581 | 49 | static int not_a_local_branch(const char *reference_name) |
1c947daa | 50 | { |
bf031581 | 51 | giterr_set( |
52 | GITERR_INVALID, | |
53 | "Reference '%s' is not a local branch.", reference_name); | |
1c947daa VM |
54 | return -1; |
55 | } | |
56 | ||
731df570 | 57 | int git_branch_create( |
d00d5464 ET |
58 | git_reference **ref_out, |
59 | git_repository *repository, | |
60 | const char *branch_name, | |
61 | const git_commit *commit, | |
62 | int force) | |
731df570 | 63 | { |
731df570 | 64 | git_reference *branch = NULL; |
65 | git_buf canonical_branch_name = GIT_BUF_INIT; | |
66 | int error = -1; | |
67 | ||
cfbe4be3 VM |
68 | assert(branch_name && commit && ref_out); |
69 | assert(git_object_owner((const git_object *)commit) == repository); | |
731df570 | 70 | |
71 | if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) | |
72 | goto cleanup; | |
73 | ||
2508cc66 | 74 | error = git_reference_create(&branch, repository, |
cfbe4be3 | 75 | git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force); |
731df570 | 76 | |
62993b61 | 77 | if (!error) |
78 | *ref_out = branch; | |
731df570 | 79 | |
80 | cleanup: | |
731df570 | 81 | git_buf_free(&canonical_branch_name); |
82 | return error; | |
83 | } | |
84 | ||
1c947daa | 85 | int git_branch_delete(git_reference *branch) |
731df570 | 86 | { |
4ba23be1 | 87 | int is_head; |
aba70781 | 88 | git_buf config_section = GIT_BUF_INIT; |
89 | int error = -1; | |
731df570 | 90 | |
1c947daa | 91 | assert(branch); |
731df570 | 92 | |
1c947daa VM |
93 | if (!git_reference_is_branch(branch) && |
94 | !git_reference_is_remote(branch)) { | |
95 | giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch)); | |
96 | return -1; | |
97 | } | |
731df570 | 98 | |
4ba23be1 | 99 | if ((is_head = git_branch_is_head(branch)) < 0) |
100 | return is_head; | |
731df570 | 101 | |
4ba23be1 | 102 | if (is_head) { |
103 | giterr_set(GITERR_REFERENCE, | |
104 | "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch)); | |
105 | return -1; | |
731df570 | 106 | } |
107 | ||
aba70781 | 108 | if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) |
109 | goto on_error; | |
110 | ||
111 | if (git_config_rename_section( | |
0b98a8a4 | 112 | git_reference_owner(branch), |
aba70781 | 113 | git_buf_cstr(&config_section), |
383f164a | 114 | NULL) < 0) |
0b98a8a4 | 115 | goto on_error; |
116 | ||
aba70781 | 117 | if (git_reference_delete(branch) < 0) |
118 | goto on_error; | |
119 | ||
120 | error = 0; | |
121 | ||
122 | on_error: | |
123 | git_buf_free(&config_section); | |
124 | return error; | |
731df570 | 125 | } |
126 | ||
a8fd805e | 127 | typedef struct { |
d00d5464 | 128 | git_branch_foreach_cb branch_cb; |
a8fd805e | 129 | void *callback_payload; |
130 | unsigned int branch_type; | |
131 | } branch_foreach_filter; | |
132 | ||
133 | static int branch_foreach_cb(const char *branch_name, void *payload) | |
134 | { | |
135 | branch_foreach_filter *filter = (branch_foreach_filter *)payload; | |
136 | ||
137 | if (filter->branch_type & GIT_BRANCH_LOCAL && | |
138 | git__prefixcmp(branch_name, GIT_REFS_HEADS_DIR) == 0) | |
139 | return filter->branch_cb(branch_name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, filter->callback_payload); | |
140 | ||
141 | if (filter->branch_type & GIT_BRANCH_REMOTE && | |
142 | git__prefixcmp(branch_name, GIT_REFS_REMOTES_DIR) == 0) | |
143 | return filter->branch_cb(branch_name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, filter->callback_payload); | |
144 | ||
145 | return 0; | |
146 | } | |
147 | ||
148 | int git_branch_foreach( | |
d00d5464 ET |
149 | git_repository *repo, |
150 | unsigned int list_flags, | |
151 | git_branch_foreach_cb branch_cb, | |
152 | void *payload) | |
a8fd805e | 153 | { |
154 | branch_foreach_filter filter; | |
155 | ||
156 | filter.branch_cb = branch_cb; | |
157 | filter.branch_type = list_flags; | |
158 | filter.callback_payload = payload; | |
159 | ||
160 | return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter); | |
161 | } | |
162 | ||
bf9e8cc8 | 163 | int git_branch_move( |
d00d5464 | 164 | git_reference **out, |
bf9e8cc8 | 165 | git_reference *branch, |
166 | const char *new_branch_name, | |
167 | int force) | |
168 | { | |
383f164a | 169 | git_buf new_reference_name = GIT_BUF_INIT, |
aba70781 | 170 | old_config_section = GIT_BUF_INIT, |
171 | new_config_section = GIT_BUF_INIT; | |
bf9e8cc8 | 172 | int error; |
6a8bcfa4 | 173 | |
bf9e8cc8 | 174 | assert(branch && new_branch_name); |
175 | ||
176 | if (!git_reference_is_branch(branch)) | |
bf031581 | 177 | return not_a_local_branch(git_reference_name(branch)); |
4615f0f7 | 178 | |
d00d5464 | 179 | if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0 || |
10c06114 | 180 | (error = git_buf_printf(&old_config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR))) < 0 || |
d00d5464 ET |
181 | (error = git_buf_printf(&new_config_section, "branch.%s", new_branch_name)) < 0) |
182 | goto done; | |
383f164a | 183 | |
d00d5464 | 184 | if ((error = git_config_rename_section(git_reference_owner(branch), |
aba70781 | 185 | git_buf_cstr(&old_config_section), |
186 | git_buf_cstr(&new_config_section))) < 0) | |
d00d5464 | 187 | goto done; |
3e199f42 | 188 | |
d00d5464 ET |
189 | if ((error = git_reference_rename(out, branch, git_buf_cstr(&new_reference_name), force)) < 0) |
190 | goto done; | |
4615f0f7 | 191 | |
d00d5464 | 192 | done: |
6a8bcfa4 | 193 | git_buf_free(&new_reference_name); |
aba70781 | 194 | git_buf_free(&old_config_section); |
195 | git_buf_free(&new_config_section); | |
6a8bcfa4 | 196 | |
6a625435 | 197 | return error; |
4615f0f7 | 198 | } |
eed378b6 | 199 | |
200 | int git_branch_lookup( | |
d00d5464 ET |
201 | git_reference **ref_out, |
202 | git_repository *repo, | |
203 | const char *branch_name, | |
204 | git_branch_t branch_type) | |
eed378b6 | 205 | { |
206 | assert(ref_out && repo && branch_name); | |
207 | ||
208 | return retrieve_branch_reference(ref_out, repo, branch_name, branch_type == GIT_BRANCH_REMOTE); | |
209 | } | |
fb910281 | 210 | |
c253056d SB |
211 | int git_branch_name(const char **out, git_reference *ref) |
212 | { | |
213 | const char *branch_name; | |
214 | ||
215 | assert(out && ref); | |
216 | ||
217 | branch_name = ref->name; | |
218 | ||
219 | if (git_reference_is_branch(ref)) { | |
220 | branch_name += strlen(GIT_REFS_HEADS_DIR); | |
221 | } else if (git_reference_is_remote(ref)) { | |
222 | branch_name += strlen(GIT_REFS_REMOTES_DIR); | |
223 | } else { | |
224 | giterr_set(GITERR_INVALID, | |
225 | "Reference '%s' is neither a local nor a remote branch.", ref->name); | |
226 | return -1; | |
227 | } | |
228 | *out = branch_name; | |
229 | return 0; | |
230 | } | |
231 | ||
a258d8e3 | 232 | static int retrieve_upstream_configuration( |
bf031581 | 233 | const char **out, |
234 | git_repository *repo, | |
235 | const char *canonical_branch_name, | |
236 | const char *format) | |
fb910281 | 237 | { |
238 | git_config *config; | |
239 | git_buf buf = GIT_BUF_INIT; | |
240 | int error; | |
241 | ||
bf031581 | 242 | if (git_repository_config__weakptr(&config, repo) < 0) |
fb910281 | 243 | return -1; |
244 | ||
245 | if (git_buf_printf(&buf, format, | |
bf031581 | 246 | canonical_branch_name + strlen(GIT_REFS_HEADS_DIR)) < 0) |
fb910281 | 247 | return -1; |
248 | ||
249 | error = git_config_get_string(out, config, git_buf_cstr(&buf)); | |
250 | git_buf_free(&buf); | |
251 | return error; | |
252 | } | |
253 | ||
a258d8e3 | 254 | int git_branch_upstream__name( |
bf031581 | 255 | git_buf *tracking_name, |
256 | git_repository *repo, | |
257 | const char *canonical_branch_name) | |
fb910281 | 258 | { |
259 | const char *remote_name, *merge_name; | |
260 | git_buf buf = GIT_BUF_INIT; | |
261 | int error = -1; | |
262 | git_remote *remote = NULL; | |
263 | const git_refspec *refspec; | |
264 | ||
bf031581 | 265 | assert(tracking_name && canonical_branch_name); |
fb910281 | 266 | |
bf031581 | 267 | if (!git_reference__is_branch(canonical_branch_name)) |
268 | return not_a_local_branch(canonical_branch_name); | |
fb910281 | 269 | |
a258d8e3 | 270 | if ((error = retrieve_upstream_configuration( |
bf031581 | 271 | &remote_name, repo, canonical_branch_name, "branch.%s.remote")) < 0) |
272 | goto cleanup; | |
fb910281 | 273 | |
a258d8e3 | 274 | if ((error = retrieve_upstream_configuration( |
bf031581 | 275 | &merge_name, repo, canonical_branch_name, "branch.%s.merge")) < 0) |
276 | goto cleanup; | |
37849a8e | 277 | |
28cbd2e2 | 278 | if (!*remote_name || !*merge_name) { |
3e199f42 RB |
279 | giterr_set(GITERR_REFERENCE, |
280 | "branch '%s' does not have an upstream", canonical_branch_name); | |
28cbd2e2 | 281 | error = GIT_ENOTFOUND; |
282 | goto cleanup; | |
283 | } | |
fb910281 | 284 | |
285 | if (strcmp(".", remote_name) != 0) { | |
bf031581 | 286 | if ((error = git_remote_load(&remote, repo, remote_name)) < 0) |
fb910281 | 287 | goto cleanup; |
288 | ||
4330ab26 CMN |
289 | refspec = git_remote__matching_refspec(remote, merge_name); |
290 | if (!refspec) { | |
291 | error = GIT_ENOTFOUND; | |
292 | goto cleanup; | |
fb910281 | 293 | } |
294 | ||
295 | if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) | |
296 | goto cleanup; | |
297 | } else | |
298 | if (git_buf_sets(&buf, merge_name) < 0) | |
299 | goto cleanup; | |
300 | ||
bf031581 | 301 | error = git_buf_set(tracking_name, git_buf_cstr(&buf), git_buf_len(&buf)); |
fb910281 | 302 | |
303 | cleanup: | |
304 | git_remote_free(remote); | |
305 | git_buf_free(&buf); | |
306 | return error; | |
307 | } | |
0c78f685 | 308 | |
97016f29 | 309 | static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name) |
2e3e8c88 JM |
310 | { |
311 | git_strarray remote_list = {0}; | |
97016f29 | 312 | size_t i; |
2e3e8c88 JM |
313 | git_remote *remote; |
314 | const git_refspec *fetchspec; | |
315 | int error = 0; | |
316 | char *remote_name = NULL; | |
317 | ||
97016f29 | 318 | assert(buf && repo && canonical_branch_name); |
2e3e8c88 JM |
319 | |
320 | /* Verify that this is a remote branch */ | |
c1b5e8c4 | 321 | if (!git_reference__is_remote(canonical_branch_name)) { |
322 | giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.", | |
323 | canonical_branch_name); | |
2e3e8c88 JM |
324 | error = GIT_ERROR; |
325 | goto cleanup; | |
326 | } | |
327 | ||
328 | /* Get the remotes */ | |
329 | if ((error = git_remote_list(&remote_list, repo)) < 0) | |
330 | goto cleanup; | |
331 | ||
332 | /* Find matching remotes */ | |
333 | for (i = 0; i < remote_list.count; i++) { | |
334 | if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) | |
d59942c2 | 335 | continue; |
2e3e8c88 | 336 | |
4330ab26 CMN |
337 | fetchspec = git_remote__matching_dst_refspec(remote, canonical_branch_name); |
338 | if (fetchspec) { | |
2e3e8c88 JM |
339 | /* If we have not already set out yet, then set |
340 | * it to the matching remote name. Otherwise | |
341 | * multiple remotes match this reference, and it | |
342 | * is ambiguous. */ | |
343 | if (!remote_name) { | |
344 | remote_name = remote_list.strings[i]; | |
345 | } else { | |
346 | git_remote_free(remote); | |
3e199f42 RB |
347 | |
348 | giterr_set(GITERR_REFERENCE, | |
349 | "Reference '%s' is ambiguous", canonical_branch_name); | |
2e3e8c88 JM |
350 | error = GIT_EAMBIGUOUS; |
351 | goto cleanup; | |
352 | } | |
353 | } | |
354 | ||
355 | git_remote_free(remote); | |
356 | } | |
357 | ||
358 | if (remote_name) { | |
97016f29 CMN |
359 | git_buf_clear(buf); |
360 | error = git_buf_puts(buf, remote_name); | |
2e3e8c88 | 361 | } else { |
3e199f42 RB |
362 | giterr_set(GITERR_REFERENCE, |
363 | "Could not determine remote for '%s'", canonical_branch_name); | |
2e3e8c88 | 364 | error = GIT_ENOTFOUND; |
2e3e8c88 JM |
365 | } |
366 | ||
367 | cleanup: | |
368 | git_strarray_free(&remote_list); | |
369 | return error; | |
370 | } | |
371 | ||
97016f29 CMN |
372 | int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname) |
373 | { | |
374 | int ret; | |
375 | git_buf buf = GIT_BUF_INIT; | |
376 | ||
377 | if ((ret = remote_name(&buf, repo, refname)) < 0) | |
378 | return ret; | |
379 | ||
380 | if (buffer) | |
381 | git_buf_copy_cstr(buffer, buffer_len, &buf); | |
382 | ||
38fd8121 | 383 | ret = (int)git_buf_len(&buf) + 1; |
97016f29 CMN |
384 | git_buf_free(&buf); |
385 | ||
386 | return ret; | |
387 | } | |
388 | ||
a258d8e3 | 389 | int git_branch_upstream_name( |
bf031581 | 390 | char *tracking_branch_name_out, |
391 | size_t buffer_size, | |
392 | git_repository *repo, | |
393 | const char *canonical_branch_name) | |
394 | { | |
395 | git_buf buf = GIT_BUF_INIT; | |
396 | int error; | |
397 | ||
398 | assert(canonical_branch_name); | |
399 | ||
400 | if (tracking_branch_name_out && buffer_size) | |
401 | *tracking_branch_name_out = '\0'; | |
402 | ||
a258d8e3 | 403 | if ((error = git_branch_upstream__name( |
bf031581 | 404 | &buf, repo, canonical_branch_name)) < 0) |
405 | goto cleanup; | |
406 | ||
407 | if (tracking_branch_name_out && buf.size + 1 > buffer_size) { /* +1 for NUL byte */ | |
408 | giterr_set( | |
409 | GITERR_INVALID, | |
410 | "Buffer too short to hold the tracked reference name."); | |
411 | error = -1; | |
412 | goto cleanup; | |
413 | } | |
414 | ||
415 | if (tracking_branch_name_out) | |
416 | git_buf_copy_cstr(tracking_branch_name_out, buffer_size, &buf); | |
417 | ||
3ad05221 | 418 | error = (int)buf.size + 1; |
bf031581 | 419 | |
420 | cleanup: | |
421 | git_buf_free(&buf); | |
422 | return (int)error; | |
423 | } | |
424 | ||
a258d8e3 | 425 | int git_branch_upstream( |
bf031581 | 426 | git_reference **tracking_out, |
427 | git_reference *branch) | |
428 | { | |
429 | int error; | |
430 | git_buf tracking_name = GIT_BUF_INIT; | |
431 | ||
a258d8e3 | 432 | if ((error = git_branch_upstream__name(&tracking_name, |
bf031581 | 433 | git_reference_owner(branch), git_reference_name(branch))) < 0) |
434 | return error; | |
435 | ||
436 | error = git_reference_lookup( | |
437 | tracking_out, | |
438 | git_reference_owner(branch), | |
439 | git_buf_cstr(&tracking_name)); | |
440 | ||
441 | git_buf_free(&tracking_name); | |
442 | return error; | |
443 | } | |
444 | ||
d59942c2 CMN |
445 | static int unset_upstream(git_config *config, const char *shortname) |
446 | { | |
447 | git_buf buf = GIT_BUF_INIT; | |
448 | ||
449 | if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0) | |
450 | return -1; | |
451 | ||
452 | if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) | |
453 | goto on_error; | |
454 | ||
455 | git_buf_clear(&buf); | |
456 | if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0) | |
457 | goto on_error; | |
458 | ||
459 | if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) | |
460 | goto on_error; | |
461 | ||
462 | git_buf_free(&buf); | |
463 | return 0; | |
464 | ||
465 | on_error: | |
466 | git_buf_free(&buf); | |
467 | return -1; | |
468 | } | |
469 | ||
470 | int git_branch_set_upstream(git_reference *branch, const char *upstream_name) | |
471 | { | |
472 | git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; | |
473 | git_reference *upstream; | |
474 | git_repository *repo; | |
475 | git_remote *remote = NULL; | |
476 | git_config *config; | |
477 | const char *name, *shortname; | |
478 | int local; | |
479 | const git_refspec *fetchspec; | |
480 | ||
481 | name = git_reference_name(branch); | |
482 | if (!git_reference__is_branch(name)) | |
483 | return not_a_local_branch(name); | |
484 | ||
485 | if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) | |
486 | return -1; | |
487 | ||
488 | shortname = name + strlen(GIT_REFS_HEADS_DIR); | |
489 | ||
490 | if (upstream_name == NULL) | |
491 | return unset_upstream(config, shortname); | |
492 | ||
493 | repo = git_reference_owner(branch); | |
494 | ||
495 | /* First we need to figure out whether it's a branch or remote-tracking */ | |
496 | if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) | |
497 | local = 1; | |
498 | else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) | |
499 | local = 0; | |
3e199f42 RB |
500 | else { |
501 | giterr_set(GITERR_REFERENCE, | |
502 | "Cannot set upstream for branch '%s'", shortname); | |
d59942c2 | 503 | return GIT_ENOTFOUND; |
3e199f42 | 504 | } |
d59942c2 CMN |
505 | |
506 | /* | |
507 | * If it's local, the remote is "." and the branch name is | |
508 | * simply the refname. Otherwise we need to figure out what | |
509 | * the remote-tracking branch's name on the remote is and use | |
510 | * that. | |
511 | */ | |
512 | if (local) | |
513 | git_buf_puts(&value, "."); | |
514 | else | |
515 | remote_name(&value, repo, git_reference_name(upstream)); | |
516 | ||
517 | if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) | |
518 | goto on_error; | |
519 | ||
520 | if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) | |
521 | goto on_error; | |
522 | ||
523 | if (local) { | |
524 | if (git_buf_puts(&value, git_reference_name(branch)) < 0) | |
525 | goto on_error; | |
526 | } else { | |
527 | /* Get the remoe-tracking branch's refname in its repo */ | |
528 | if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) | |
529 | goto on_error; | |
530 | ||
4330ab26 | 531 | fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); |
d59942c2 | 532 | git_buf_clear(&value); |
4330ab26 | 533 | if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) |
d59942c2 CMN |
534 | goto on_error; |
535 | ||
536 | git_remote_free(remote); | |
537 | remote = NULL; | |
538 | } | |
539 | ||
540 | git_buf_clear(&key); | |
541 | if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) | |
542 | goto on_error; | |
543 | ||
544 | if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) | |
545 | goto on_error; | |
546 | ||
547 | git_reference_free(upstream); | |
548 | git_buf_free(&key); | |
549 | git_buf_free(&value); | |
550 | ||
551 | return 0; | |
552 | ||
553 | on_error: | |
554 | git_reference_free(upstream); | |
555 | git_buf_free(&key); | |
556 | git_buf_free(&value); | |
557 | git_remote_free(remote); | |
558 | ||
559 | return -1; | |
560 | } | |
561 | ||
0c78f685 | 562 | int git_branch_is_head( |
563 | git_reference *branch) | |
564 | { | |
565 | git_reference *head; | |
566 | bool is_same = false; | |
0532e7bb | 567 | int error; |
0c78f685 | 568 | |
569 | assert(branch); | |
570 | ||
571 | if (!git_reference_is_branch(branch)) | |
572 | return false; | |
573 | ||
0532e7bb | 574 | error = git_repository_head(&head, git_reference_owner(branch)); |
575 | ||
b1a3a70e | 576 | if (error == GIT_EORPHANEDHEAD || error == GIT_ENOTFOUND) |
0532e7bb | 577 | return false; |
578 | ||
579 | if (error < 0) | |
0c78f685 | 580 | return -1; |
581 | ||
582 | is_same = strcmp( | |
583 | git_reference_name(branch), | |
584 | git_reference_name(head)) == 0; | |
585 | ||
586 | git_reference_free(head); | |
587 | ||
588 | return is_same; | |
589 | } |