|
12 | 12 | #include "builtin.h" |
13 | 13 | #include "remote.h" |
14 | 14 | #include "parse-options.h" |
| 15 | +#include "branch.h" |
15 | 16 |
|
16 | 17 | static const char * const builtin_branch_usage[] = { |
17 | 18 | "git-branch [options] [-r | -a]", |
@@ -356,141 +357,6 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str |
356 | 357 | free_ref_list(&ref_list); |
357 | 358 | } |
358 | 359 |
|
359 | | -struct tracking { |
360 | | - struct refspec spec; |
361 | | - char *src; |
362 | | - const char *remote; |
363 | | - int matches; |
364 | | -}; |
365 | | - |
366 | | -static int find_tracked_branch(struct remote *remote, void *priv) |
367 | | -{ |
368 | | - struct tracking *tracking = priv; |
369 | | - |
370 | | - if (!remote_find_tracking(remote, &tracking->spec)) { |
371 | | - if (++tracking->matches == 1) { |
372 | | - tracking->src = tracking->spec.src; |
373 | | - tracking->remote = remote->name; |
374 | | - } else { |
375 | | - free(tracking->spec.src); |
376 | | - if (tracking->src) { |
377 | | - free(tracking->src); |
378 | | - tracking->src = NULL; |
379 | | - } |
380 | | - } |
381 | | - tracking->spec.src = NULL; |
382 | | - } |
383 | | - |
384 | | - return 0; |
385 | | -} |
386 | | - |
387 | | - |
388 | | -/* |
389 | | - * This is called when new_ref is branched off of orig_ref, and tries |
390 | | - * to infer the settings for branch.<new_ref>.{remote,merge} from the |
391 | | - * config. |
392 | | - */ |
393 | | -static int setup_tracking(const char *new_ref, const char *orig_ref) |
394 | | -{ |
395 | | - char key[1024]; |
396 | | - struct tracking tracking; |
397 | | - |
398 | | - if (strlen(new_ref) > 1024 - 7 - 7 - 1) |
399 | | - return error("Tracking not set up: name too long: %s", |
400 | | - new_ref); |
401 | | - |
402 | | - memset(&tracking, 0, sizeof(tracking)); |
403 | | - tracking.spec.dst = (char *)orig_ref; |
404 | | - if (for_each_remote(find_tracked_branch, &tracking) || |
405 | | - !tracking.matches) |
406 | | - return 1; |
407 | | - |
408 | | - if (tracking.matches > 1) |
409 | | - return error("Not tracking: ambiguous information for ref %s", |
410 | | - orig_ref); |
411 | | - |
412 | | - if (tracking.matches == 1) { |
413 | | - sprintf(key, "branch.%s.remote", new_ref); |
414 | | - git_config_set(key, tracking.remote ? tracking.remote : "."); |
415 | | - sprintf(key, "branch.%s.merge", new_ref); |
416 | | - git_config_set(key, tracking.src); |
417 | | - free(tracking.src); |
418 | | - printf("Branch %s set up to track remote branch %s.\n", |
419 | | - new_ref, orig_ref); |
420 | | - } |
421 | | - |
422 | | - return 0; |
423 | | -} |
424 | | - |
425 | | -static void create_branch(const char *name, const char *start_name, |
426 | | - int force, int reflog, int track) |
427 | | -{ |
428 | | - struct ref_lock *lock; |
429 | | - struct commit *commit; |
430 | | - unsigned char sha1[20]; |
431 | | - char *real_ref, ref[PATH_MAX], msg[PATH_MAX + 20]; |
432 | | - int forcing = 0; |
433 | | - |
434 | | - snprintf(ref, sizeof ref, "refs/heads/%s", name); |
435 | | - if (check_ref_format(ref)) |
436 | | - die("'%s' is not a valid branch name.", name); |
437 | | - |
438 | | - if (resolve_ref(ref, sha1, 1, NULL)) { |
439 | | - if (!force) |
440 | | - die("A branch named '%s' already exists.", name); |
441 | | - else if (!is_bare_repository() && !strcmp(head, name)) |
442 | | - die("Cannot force update the current branch."); |
443 | | - forcing = 1; |
444 | | - } |
445 | | - |
446 | | - real_ref = NULL; |
447 | | - if (get_sha1(start_name, sha1)) |
448 | | - die("Not a valid object name: '%s'.", start_name); |
449 | | - |
450 | | - switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { |
451 | | - case 0: |
452 | | - /* Not branching from any existing branch */ |
453 | | - real_ref = NULL; |
454 | | - break; |
455 | | - case 1: |
456 | | - /* Unique completion -- good */ |
457 | | - break; |
458 | | - default: |
459 | | - die("Ambiguous object name: '%s'.", start_name); |
460 | | - break; |
461 | | - } |
462 | | - |
463 | | - if ((commit = lookup_commit_reference(sha1)) == NULL) |
464 | | - die("Not a valid branch point: '%s'.", start_name); |
465 | | - hashcpy(sha1, commit->object.sha1); |
466 | | - |
467 | | - lock = lock_any_ref_for_update(ref, NULL, 0); |
468 | | - if (!lock) |
469 | | - die("Failed to lock ref for update: %s.", strerror(errno)); |
470 | | - |
471 | | - if (reflog) |
472 | | - log_all_ref_updates = 1; |
473 | | - |
474 | | - if (forcing) |
475 | | - snprintf(msg, sizeof msg, "branch: Reset from %s", |
476 | | - start_name); |
477 | | - else |
478 | | - snprintf(msg, sizeof msg, "branch: Created from %s", |
479 | | - start_name); |
480 | | - |
481 | | - /* When branching off a remote branch, set up so that git-pull |
482 | | - automatically merges from there. So far, this is only done for |
483 | | - remotes registered via .git/config. */ |
484 | | - if (real_ref && track) |
485 | | - setup_tracking(name, real_ref); |
486 | | - |
487 | | - if (write_ref_sha1(lock, sha1, msg) < 0) |
488 | | - die("Failed to write ref: %s.", strerror(errno)); |
489 | | - |
490 | | - if (real_ref) |
491 | | - free(real_ref); |
492 | | -} |
493 | | - |
494 | 360 | static void rename_branch(const char *oldname, const char *newname, int force) |
495 | 361 | { |
496 | 362 | char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100]; |
@@ -611,7 +477,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) |
611 | 477 | else if (rename && (argc == 2)) |
612 | 478 | rename_branch(argv[0], argv[1], rename > 1); |
613 | 479 | else if (argc <= 2) |
614 | | - create_branch(argv[0], (argc == 2) ? argv[1] : head, |
| 480 | + create_branch(head, argv[0], (argc == 2) ? argv[1] : head, |
615 | 481 | force_create, reflog, track); |
616 | 482 | else |
617 | 483 | usage_with_options(builtin_branch_usage, options); |
|
0 commit comments