|
8 | 8 | #include "sequencer.h"
|
9 | 9 | #include "commit.h"
|
10 | 10 | #include "worktree.h"
|
| 11 | +#include "submodule-config.h" |
| 12 | +#include "run-command.h" |
11 | 13 |
|
12 | 14 | struct tracking {
|
13 | 15 | struct refspec_item spec;
|
@@ -483,6 +485,145 @@ void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
|
483 | 485 | setup_tracking(new_ref, real_orig_ref, track, quiet);
|
484 | 486 | }
|
485 | 487 |
|
| 488 | +/** |
| 489 | + * Creates a branch in a submodule by calling |
| 490 | + * create_branches_recursively() in a child process. The child process |
| 491 | + * is necessary because install_branch_config_multiple_remotes() (which |
| 492 | + * is called by setup_tracking()) does not support writing configs to |
| 493 | + * submodules. |
| 494 | + */ |
| 495 | +static int submodule_create_branch(struct repository *r, |
| 496 | + const struct submodule *submodule, |
| 497 | + const char *name, const char *start_oid, |
| 498 | + const char *tracking_name, int force, |
| 499 | + int reflog, int quiet, |
| 500 | + enum branch_track track, int dry_run) |
| 501 | +{ |
| 502 | + int ret = 0; |
| 503 | + struct child_process child = CHILD_PROCESS_INIT; |
| 504 | + struct strbuf child_err = STRBUF_INIT; |
| 505 | + struct strbuf out_buf = STRBUF_INIT; |
| 506 | + char *out_prefix = xstrfmt("submodule '%s': ", submodule->name); |
| 507 | + child.git_cmd = 1; |
| 508 | + child.err = -1; |
| 509 | + child.stdout_to_stderr = 1; |
| 510 | + |
| 511 | + prepare_other_repo_env(&child.env_array, r->gitdir); |
| 512 | + /* |
| 513 | + * submodule_create_branch() is indirectly invoked by "git |
| 514 | + * branch", but we cannot invoke "git branch" in the child |
| 515 | + * process. "git branch" accepts a branch name and start point, |
| 516 | + * where the start point is assumed to provide both the OID |
| 517 | + * (start_oid) and the branch to use for tracking |
| 518 | + * (tracking_name). But when recursing through submodules, |
| 519 | + * start_oid and tracking name need to be specified separately |
| 520 | + * (see create_branches_recursively()). |
| 521 | + */ |
| 522 | + strvec_pushl(&child.args, "submodule--helper", "create-branch", NULL); |
| 523 | + if (dry_run) |
| 524 | + strvec_push(&child.args, "--dry-run"); |
| 525 | + if (force) |
| 526 | + strvec_push(&child.args, "--force"); |
| 527 | + if (quiet) |
| 528 | + strvec_push(&child.args, "--quiet"); |
| 529 | + if (reflog) |
| 530 | + strvec_push(&child.args, "--create-reflog"); |
| 531 | + if (track == BRANCH_TRACK_ALWAYS || track == BRANCH_TRACK_EXPLICIT) |
| 532 | + strvec_push(&child.args, "--track"); |
| 533 | + |
| 534 | + strvec_pushl(&child.args, name, start_oid, tracking_name, NULL); |
| 535 | + |
| 536 | + if ((ret = start_command(&child))) |
| 537 | + return ret; |
| 538 | + ret = finish_command(&child); |
| 539 | + strbuf_read(&child_err, child.err, 0); |
| 540 | + strbuf_add_lines(&out_buf, out_prefix, child_err.buf, child_err.len); |
| 541 | + |
| 542 | + if (ret) |
| 543 | + fprintf(stderr, "%s", out_buf.buf); |
| 544 | + else |
| 545 | + printf("%s", out_buf.buf); |
| 546 | + |
| 547 | + strbuf_release(&child_err); |
| 548 | + strbuf_release(&out_buf); |
| 549 | + return ret; |
| 550 | +} |
| 551 | + |
| 552 | +void create_branches_recursively(struct repository *r, const char *name, |
| 553 | + const char *start_commitish, |
| 554 | + const char *tracking_name, int force, |
| 555 | + int reflog, int quiet, enum branch_track track, |
| 556 | + int dry_run) |
| 557 | +{ |
| 558 | + int i = 0; |
| 559 | + char *branch_point = NULL; |
| 560 | + struct object_id super_oid; |
| 561 | + struct submodule_entry_list submodule_entry_list; |
| 562 | + |
| 563 | + /* Perform dwim on start_commitish to get super_oid and branch_point. */ |
| 564 | + dwim_branch_start(r, start_commitish, BRANCH_TRACK_NEVER, |
| 565 | + &branch_point, &super_oid); |
| 566 | + |
| 567 | + /* |
| 568 | + * If we were not given an explicit name to track, then assume we are at |
| 569 | + * the top level and, just like the non-recursive case, the tracking |
| 570 | + * name is the branch point. |
| 571 | + */ |
| 572 | + if (!tracking_name) |
| 573 | + tracking_name = branch_point; |
| 574 | + |
| 575 | + submodules_of_tree(r, &super_oid, &submodule_entry_list); |
| 576 | + /* |
| 577 | + * Before creating any branches, first check that the branch can |
| 578 | + * be created in every submodule. |
| 579 | + */ |
| 580 | + for (i = 0; i < submodule_entry_list.entry_nr; i++) { |
| 581 | + if (submodule_entry_list.entries[i].repo == NULL) { |
| 582 | + if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED)) |
| 583 | + advise(_("You may try updating the submodules using 'git checkout %s && git submodule update --init'"), |
| 584 | + start_commitish); |
| 585 | + die(_("submodule '%s': unable to find submodule"), |
| 586 | + submodule_entry_list.entries[i].submodule->name); |
| 587 | + } |
| 588 | + |
| 589 | + if (submodule_create_branch( |
| 590 | + submodule_entry_list.entries[i].repo, |
| 591 | + submodule_entry_list.entries[i].submodule, name, |
| 592 | + oid_to_hex(&submodule_entry_list.entries[i] |
| 593 | + .name_entry->oid), |
| 594 | + tracking_name, force, reflog, quiet, track, 1)) |
| 595 | + die(_("submodule '%s': cannot create branch '%s'"), |
| 596 | + submodule_entry_list.entries[i].submodule->name, |
| 597 | + name); |
| 598 | + } |
| 599 | + |
| 600 | + create_branch(the_repository, name, start_commitish, force, 0, reflog, quiet, |
| 601 | + BRANCH_TRACK_NEVER, dry_run); |
| 602 | + if (dry_run) |
| 603 | + return; |
| 604 | + /* |
| 605 | + * NEEDSWORK If tracking was set up in the superproject but not the |
| 606 | + * submodule, users might expect "git branch --recurse-submodules" to |
| 607 | + * fail or give a warning, but this is not yet implemented because it is |
| 608 | + * tedious to determine whether or not tracking was set up in the |
| 609 | + * superproject. |
| 610 | + */ |
| 611 | + setup_tracking(name, tracking_name, track, quiet); |
| 612 | + |
| 613 | + for (i = 0; i < submodule_entry_list.entry_nr; i++) { |
| 614 | + if (submodule_create_branch( |
| 615 | + submodule_entry_list.entries[i].repo, |
| 616 | + submodule_entry_list.entries[i].submodule, name, |
| 617 | + oid_to_hex(&submodule_entry_list.entries[i] |
| 618 | + .name_entry->oid), |
| 619 | + tracking_name, force, reflog, quiet, track, 0)) |
| 620 | + die(_("submodule '%s': cannot create branch '%s'"), |
| 621 | + submodule_entry_list.entries[i].submodule->name, |
| 622 | + name); |
| 623 | + repo_clear(submodule_entry_list.entries[i].repo); |
| 624 | + } |
| 625 | +} |
| 626 | + |
486 | 627 | void remove_merge_branch_state(struct repository *r)
|
487 | 628 | {
|
488 | 629 | unlink(git_path_merge_head(r));
|
|
0 commit comments