diff options
Diffstat (limited to 'branch.c')
| -rw-r--r-- | branch.c | 122 |
1 files changed, 110 insertions, 12 deletions
@@ -10,6 +10,7 @@ #include "worktree.h" #include "submodule-config.h" #include "run-command.h" +#include "strmap.h" struct tracking { struct refspec_item spec; @@ -44,9 +45,9 @@ static int find_tracked_branch(struct remote *remote, void *priv) string_list_clear(tracking->srcs, 0); break; } + /* remote_find_tracking() searches by src if present */ tracking->spec.src = NULL; } - return 0; } @@ -264,15 +265,23 @@ static void setup_tracking(const char *new_ref, const char *orig_ref, if (!tracking.matches) switch (track) { + /* If ref is not remote, still use local */ case BRANCH_TRACK_ALWAYS: case BRANCH_TRACK_EXPLICIT: case BRANCH_TRACK_OVERRIDE: + /* Remote matches not evaluated */ case BRANCH_TRACK_INHERIT: break; + /* Otherwise, if no remote don't track */ default: goto cleanup; } + /* + * This check does not apply to BRANCH_TRACK_INHERIT; + * that supports multiple entries in tracking_srcs but + * leaves tracking.matches at 0. + */ if (tracking.matches > 1) { int status = die_message(_("not tracking: ambiguous information for ref '%s'"), orig_ref); @@ -307,6 +316,21 @@ static void setup_tracking(const char *new_ref, const char *orig_ref, exit(status); } + if (track == BRANCH_TRACK_SIMPLE) { + /* + * Only track if remote branch name matches. + * Reaching into items[0].string is safe because + * we know there is at least one and not more than + * one entry (because only BRANCH_TRACK_INHERIT can + * produce more than one entry). + */ + const char *tracked_branch; + if (!skip_prefix(tracking.srcs->items[0].string, + "refs/heads/", &tracked_branch) || + strcmp(tracked_branch, new_ref)) + return; + } + if (tracking.srcs->nr < 1) string_list_append(tracking.srcs, orig_ref); if (install_branch_config_multiple_remotes(config_flags, new_ref, @@ -346,6 +370,83 @@ int validate_branchname(const char *name, struct strbuf *ref) return ref_exists(ref->buf); } +static int initialized_checked_out_branches; +static struct strmap current_checked_out_branches = STRMAP_INIT; + +static void prepare_checked_out_branches(void) +{ + int i = 0; + struct worktree **worktrees; + + if (initialized_checked_out_branches) + return; + initialized_checked_out_branches = 1; + + worktrees = get_worktrees(); + + while (worktrees[i]) { + char *old; + struct wt_status_state state = { 0 }; + struct worktree *wt = worktrees[i++]; + struct string_list update_refs = STRING_LIST_INIT_DUP; + + if (wt->is_bare) + continue; + + if (wt->head_ref) { + old = strmap_put(¤t_checked_out_branches, + wt->head_ref, + xstrdup(wt->path)); + free(old); + } + + if (wt_status_check_rebase(wt, &state) && + (state.rebase_in_progress || state.rebase_interactive_in_progress) && + state.branch) { + struct strbuf ref = STRBUF_INIT; + strbuf_addf(&ref, "refs/heads/%s", state.branch); + old = strmap_put(¤t_checked_out_branches, + ref.buf, + xstrdup(wt->path)); + free(old); + strbuf_release(&ref); + } + wt_status_state_free_buffers(&state); + + if (wt_status_check_bisect(wt, &state) && + state.branch) { + struct strbuf ref = STRBUF_INIT; + strbuf_addf(&ref, "refs/heads/%s", state.branch); + old = strmap_put(¤t_checked_out_branches, + ref.buf, + xstrdup(wt->path)); + free(old); + strbuf_release(&ref); + } + wt_status_state_free_buffers(&state); + + if (!sequencer_get_update_refs_state(get_worktree_git_dir(wt), + &update_refs)) { + struct string_list_item *item; + for_each_string_list_item(item, &update_refs) { + old = strmap_put(¤t_checked_out_branches, + item->string, + xstrdup(wt->path)); + free(old); + } + string_list_clear(&update_refs, 1); + } + } + + free_worktrees(worktrees); +} + +const char *branch_checked_out(const char *refname) +{ + prepare_checked_out_branches(); + return strmap_get(¤t_checked_out_branches, refname); +} + /* * Check if a branch 'name' can be created as a new branch; die otherwise. * 'force' can be used when it is OK for the named branch already exists. @@ -354,9 +455,7 @@ int validate_branchname(const char *name, struct strbuf *ref) */ int validate_new_branchname(const char *name, struct strbuf *ref, int force) { - struct worktree **worktrees; - const struct worktree *wt; - + const char *path; if (!validate_branchname(name, ref)) return 0; @@ -364,13 +463,10 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force) die(_("a branch named '%s' already exists"), ref->buf + strlen("refs/heads/")); - worktrees = get_worktrees(); - wt = find_shared_symref(worktrees, "HEAD", ref->buf); - if (wt && !wt->is_bare) + if ((path = branch_checked_out(ref->buf))) die(_("cannot force update the branch '%s' " "checked out at '%s'"), - ref->buf + strlen("refs/heads/"), wt->path); - free_worktrees(worktrees); + ref->buf + strlen("refs/heads/"), path); return 1; } @@ -466,7 +562,7 @@ static void dwim_branch_start(struct repository *r, const char *start_name, break; } - if ((commit = lookup_commit_reference(r, &oid)) == NULL) + if (!(commit = lookup_commit_reference(r, &oid))) die(_("not a valid branch point: '%s'"), start_name); if (out_real_ref) { *out_real_ref = real_ref; @@ -564,7 +660,7 @@ static int submodule_create_branch(struct repository *r, child.err = -1; child.stdout_to_stderr = 1; - prepare_other_repo_env(&child.env_array, r->gitdir); + prepare_other_repo_env(&child.env, r->gitdir); /* * submodule_create_branch() is indirectly invoked by "git * branch", but we cannot invoke "git branch" in the child @@ -603,6 +699,8 @@ static int submodule_create_branch(struct repository *r, /* Default for "git checkout". Do not pass --track. */ case BRANCH_TRACK_REMOTE: /* Default for "git branch". Do not pass --track. */ + case BRANCH_TRACK_SIMPLE: + /* Config-driven only. Do not pass --track. */ break; } @@ -653,7 +751,7 @@ void create_branches_recursively(struct repository *r, const char *name, * be created in every submodule. */ for (i = 0; i < submodule_entry_list.entry_nr; i++) { - if (submodule_entry_list.entries[i].repo == NULL) { + if (!submodule_entry_list.entries[i].repo) { int code = die_message( _("submodule '%s': unable to find submodule"), submodule_entry_list.entries[i].submodule->name); |
