Merge branch 'ds/branch-checked-out' into ds/rebase-update-ref

* ds/branch-checked-out:
  branch: drop unused worktrees variable
  fetch: stop passing around unused worktrees variable
  branch: fix branch_checked_out() leaks
  branch: use branch_checked_out() when deleting refs
  fetch: use new branch_checked_out() and add tests
  branch: check for bisects and rebases
  branch: add branch_checked_out() helper
This commit is contained in:
Junio C Hamano
2022-07-12 08:38:42 -07:00
5 changed files with 224 additions and 45 deletions

View File

@ -10,6 +10,7 @@
#include "worktree.h"
#include "submodule-config.h"
#include "run-command.h"
#include "strmap.h"
struct tracking {
struct refspec_item spec;
@ -369,6 +370,70 @@ 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++];
if (wt->is_bare)
continue;
if (wt->head_ref) {
old = strmap_put(&current_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(&current_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(&current_checked_out_branches,
ref.buf,
xstrdup(wt->path));
free(old);
strbuf_release(&ref);
}
wt_status_state_free_buffers(&state);
}
free_worktrees(worktrees);
}
const char *branch_checked_out(const char *refname)
{
prepare_checked_out_branches();
return strmap_get(&current_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.
@ -377,9 +442,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;
@ -387,13 +450,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;
}