]>
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 ET |
187 | goto done; |
188 | ||
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) { |
279 | error = GIT_ENOTFOUND; | |
280 | goto cleanup; | |
281 | } | |
fb910281 | 282 | |
283 | if (strcmp(".", remote_name) != 0) { | |
bf031581 | 284 | if ((error = git_remote_load(&remote, repo, remote_name)) < 0) |
fb910281 | 285 | goto cleanup; |
286 | ||
4330ab26 CMN |
287 | refspec = git_remote__matching_refspec(remote, merge_name); |
288 | if (!refspec) { | |
289 | error = GIT_ENOTFOUND; | |
290 | goto cleanup; | |
fb910281 | 291 | } |
292 | ||
293 | if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) | |
294 | goto cleanup; | |
295 | } else | |
296 | if (git_buf_sets(&buf, merge_name) < 0) | |
297 | goto cleanup; | |
298 | ||
bf031581 | 299 | error = git_buf_set(tracking_name, git_buf_cstr(&buf), git_buf_len(&buf)); |
fb910281 | 300 | |
301 | cleanup: | |
302 | git_remote_free(remote); | |
303 | git_buf_free(&buf); | |
304 | return error; | |
305 | } | |
0c78f685 | 306 | |
97016f29 | 307 | static int remote_name(git_buf *buf, git_repository *repo, const char *canonical_branch_name) |
2e3e8c88 JM |
308 | { |
309 | git_strarray remote_list = {0}; | |
97016f29 | 310 | size_t i; |
2e3e8c88 JM |
311 | git_remote *remote; |
312 | const git_refspec *fetchspec; | |
313 | int error = 0; | |
314 | char *remote_name = NULL; | |
315 | ||
97016f29 | 316 | assert(buf && repo && canonical_branch_name); |
2e3e8c88 JM |
317 | |
318 | /* Verify that this is a remote branch */ | |
c1b5e8c4 | 319 | if (!git_reference__is_remote(canonical_branch_name)) { |
320 | giterr_set(GITERR_INVALID, "Reference '%s' is not a remote branch.", | |
321 | canonical_branch_name); | |
2e3e8c88 JM |
322 | error = GIT_ERROR; |
323 | goto cleanup; | |
324 | } | |
325 | ||
326 | /* Get the remotes */ | |
327 | if ((error = git_remote_list(&remote_list, repo)) < 0) | |
328 | goto cleanup; | |
329 | ||
330 | /* Find matching remotes */ | |
331 | for (i = 0; i < remote_list.count; i++) { | |
332 | if ((error = git_remote_load(&remote, repo, remote_list.strings[i])) < 0) | |
d59942c2 | 333 | continue; |
2e3e8c88 | 334 | |
4330ab26 CMN |
335 | fetchspec = git_remote__matching_dst_refspec(remote, canonical_branch_name); |
336 | if (fetchspec) { | |
2e3e8c88 JM |
337 | /* If we have not already set out yet, then set |
338 | * it to the matching remote name. Otherwise | |
339 | * multiple remotes match this reference, and it | |
340 | * is ambiguous. */ | |
341 | if (!remote_name) { | |
342 | remote_name = remote_list.strings[i]; | |
343 | } else { | |
344 | git_remote_free(remote); | |
345 | error = GIT_EAMBIGUOUS; | |
346 | goto cleanup; | |
347 | } | |
348 | } | |
349 | ||
350 | git_remote_free(remote); | |
351 | } | |
352 | ||
353 | if (remote_name) { | |
97016f29 CMN |
354 | git_buf_clear(buf); |
355 | error = git_buf_puts(buf, remote_name); | |
2e3e8c88 JM |
356 | } else { |
357 | error = GIT_ENOTFOUND; | |
2e3e8c88 JM |
358 | } |
359 | ||
360 | cleanup: | |
361 | git_strarray_free(&remote_list); | |
362 | return error; | |
363 | } | |
364 | ||
97016f29 CMN |
365 | int git_branch_remote_name(char *buffer, size_t buffer_len, git_repository *repo, const char *refname) |
366 | { | |
367 | int ret; | |
368 | git_buf buf = GIT_BUF_INIT; | |
369 | ||
370 | if ((ret = remote_name(&buf, repo, refname)) < 0) | |
371 | return ret; | |
372 | ||
373 | if (buffer) | |
374 | git_buf_copy_cstr(buffer, buffer_len, &buf); | |
375 | ||
38fd8121 | 376 | ret = (int)git_buf_len(&buf) + 1; |
97016f29 CMN |
377 | git_buf_free(&buf); |
378 | ||
379 | return ret; | |
380 | } | |
381 | ||
a258d8e3 | 382 | int git_branch_upstream_name( |
bf031581 | 383 | char *tracking_branch_name_out, |
384 | size_t buffer_size, | |
385 | git_repository *repo, | |
386 | const char *canonical_branch_name) | |
387 | { | |
388 | git_buf buf = GIT_BUF_INIT; | |
389 | int error; | |
390 | ||
391 | assert(canonical_branch_name); | |
392 | ||
393 | if (tracking_branch_name_out && buffer_size) | |
394 | *tracking_branch_name_out = '\0'; | |
395 | ||
a258d8e3 | 396 | if ((error = git_branch_upstream__name( |
bf031581 | 397 | &buf, repo, canonical_branch_name)) < 0) |
398 | goto cleanup; | |
399 | ||
400 | if (tracking_branch_name_out && buf.size + 1 > buffer_size) { /* +1 for NUL byte */ | |
401 | giterr_set( | |
402 | GITERR_INVALID, | |
403 | "Buffer too short to hold the tracked reference name."); | |
404 | error = -1; | |
405 | goto cleanup; | |
406 | } | |
407 | ||
408 | if (tracking_branch_name_out) | |
409 | git_buf_copy_cstr(tracking_branch_name_out, buffer_size, &buf); | |
410 | ||
3ad05221 | 411 | error = (int)buf.size + 1; |
bf031581 | 412 | |
413 | cleanup: | |
414 | git_buf_free(&buf); | |
415 | return (int)error; | |
416 | } | |
417 | ||
a258d8e3 | 418 | int git_branch_upstream( |
bf031581 | 419 | git_reference **tracking_out, |
420 | git_reference *branch) | |
421 | { | |
422 | int error; | |
423 | git_buf tracking_name = GIT_BUF_INIT; | |
424 | ||
a258d8e3 | 425 | if ((error = git_branch_upstream__name(&tracking_name, |
bf031581 | 426 | git_reference_owner(branch), git_reference_name(branch))) < 0) |
427 | return error; | |
428 | ||
429 | error = git_reference_lookup( | |
430 | tracking_out, | |
431 | git_reference_owner(branch), | |
432 | git_buf_cstr(&tracking_name)); | |
433 | ||
434 | git_buf_free(&tracking_name); | |
435 | return error; | |
436 | } | |
437 | ||
d59942c2 CMN |
438 | static int unset_upstream(git_config *config, const char *shortname) |
439 | { | |
440 | git_buf buf = GIT_BUF_INIT; | |
441 | ||
442 | if (git_buf_printf(&buf, "branch.%s.remote", shortname) < 0) | |
443 | return -1; | |
444 | ||
445 | if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) | |
446 | goto on_error; | |
447 | ||
448 | git_buf_clear(&buf); | |
449 | if (git_buf_printf(&buf, "branch.%s.merge", shortname) < 0) | |
450 | goto on_error; | |
451 | ||
452 | if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0) | |
453 | goto on_error; | |
454 | ||
455 | git_buf_free(&buf); | |
456 | return 0; | |
457 | ||
458 | on_error: | |
459 | git_buf_free(&buf); | |
460 | return -1; | |
461 | } | |
462 | ||
463 | int git_branch_set_upstream(git_reference *branch, const char *upstream_name) | |
464 | { | |
465 | git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; | |
466 | git_reference *upstream; | |
467 | git_repository *repo; | |
468 | git_remote *remote = NULL; | |
469 | git_config *config; | |
470 | const char *name, *shortname; | |
471 | int local; | |
472 | const git_refspec *fetchspec; | |
473 | ||
474 | name = git_reference_name(branch); | |
475 | if (!git_reference__is_branch(name)) | |
476 | return not_a_local_branch(name); | |
477 | ||
478 | if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) | |
479 | return -1; | |
480 | ||
481 | shortname = name + strlen(GIT_REFS_HEADS_DIR); | |
482 | ||
483 | if (upstream_name == NULL) | |
484 | return unset_upstream(config, shortname); | |
485 | ||
486 | repo = git_reference_owner(branch); | |
487 | ||
488 | /* First we need to figure out whether it's a branch or remote-tracking */ | |
489 | if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) | |
490 | local = 1; | |
491 | else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) | |
492 | local = 0; | |
493 | else | |
494 | return GIT_ENOTFOUND; | |
495 | ||
496 | /* | |
497 | * If it's local, the remote is "." and the branch name is | |
498 | * simply the refname. Otherwise we need to figure out what | |
499 | * the remote-tracking branch's name on the remote is and use | |
500 | * that. | |
501 | */ | |
502 | if (local) | |
503 | git_buf_puts(&value, "."); | |
504 | else | |
505 | remote_name(&value, repo, git_reference_name(upstream)); | |
506 | ||
507 | if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) | |
508 | goto on_error; | |
509 | ||
510 | if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) | |
511 | goto on_error; | |
512 | ||
513 | if (local) { | |
514 | if (git_buf_puts(&value, git_reference_name(branch)) < 0) | |
515 | goto on_error; | |
516 | } else { | |
517 | /* Get the remoe-tracking branch's refname in its repo */ | |
518 | if (git_remote_load(&remote, repo, git_buf_cstr(&value)) < 0) | |
519 | goto on_error; | |
520 | ||
4330ab26 | 521 | fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); |
d59942c2 | 522 | git_buf_clear(&value); |
4330ab26 | 523 | if (!fetchspec || git_refspec_transform_l(&value, fetchspec, git_reference_name(upstream)) < 0) |
d59942c2 CMN |
524 | goto on_error; |
525 | ||
526 | git_remote_free(remote); | |
527 | remote = NULL; | |
528 | } | |
529 | ||
530 | git_buf_clear(&key); | |
531 | if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) | |
532 | goto on_error; | |
533 | ||
534 | if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) | |
535 | goto on_error; | |
536 | ||
537 | git_reference_free(upstream); | |
538 | git_buf_free(&key); | |
539 | git_buf_free(&value); | |
540 | ||
541 | return 0; | |
542 | ||
543 | on_error: | |
544 | git_reference_free(upstream); | |
545 | git_buf_free(&key); | |
546 | git_buf_free(&value); | |
547 | git_remote_free(remote); | |
548 | ||
549 | return -1; | |
550 | } | |
551 | ||
0c78f685 | 552 | int git_branch_is_head( |
553 | git_reference *branch) | |
554 | { | |
555 | git_reference *head; | |
556 | bool is_same = false; | |
0532e7bb | 557 | int error; |
0c78f685 | 558 | |
559 | assert(branch); | |
560 | ||
561 | if (!git_reference_is_branch(branch)) | |
562 | return false; | |
563 | ||
0532e7bb | 564 | error = git_repository_head(&head, git_reference_owner(branch)); |
565 | ||
b1a3a70e | 566 | if (error == GIT_EORPHANEDHEAD || error == GIT_ENOTFOUND) |
0532e7bb | 567 | return false; |
568 | ||
569 | if (error < 0) | |
0c78f685 | 570 | return -1; |
571 | ||
572 | is_same = strcmp( | |
573 | git_reference_name(branch), | |
574 | git_reference_name(head)) == 0; | |
575 | ||
576 | git_reference_free(head); | |
577 | ||
578 | return is_same; | |
579 | } |