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