зеркало из https://github.com/microsoft/git.git
branch: accept multiple upstream branches for tracking
Add a new static variant of install_branch_config() that accepts multiple remote branch names for tracking. This will be used in an upcoming commit that enables inheriting the tracking configuration from a parent branch. Currently, all callers of install_branch_config() pass only a single remote. Make install_branch_config() a small wrapper around install_branch_config_multiple_remotes() so that existing callers do not need to be changed. Signed-off-by: Josh Steadmon <steadmon@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
f443b226ca
Коммит
a3f40ec4b0
145
branch.c
145
branch.c
|
@ -49,25 +49,46 @@ static int should_setup_rebase(const char *origin)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char tracking_advice[] =
|
/**
|
||||||
N_("\n"
|
* Install upstream tracking configuration for a branch; specifically, add
|
||||||
"After fixing the error cause you may try to fix up\n"
|
* `branch.<name>.remote` and `branch.<name>.merge` entries.
|
||||||
"the remote tracking information by invoking\n"
|
*
|
||||||
"\"git branch --set-upstream-to=%s%s%s\".");
|
* `flag` contains integer flags for options; currently only
|
||||||
|
* BRANCH_CONFIG_VERBOSE is checked.
|
||||||
int install_branch_config(int flag, const char *local, const char *origin, const char *remote)
|
*
|
||||||
|
* `local` is the name of the branch whose configuration we're installing.
|
||||||
|
*
|
||||||
|
* `origin` is the name of the remote owning the upstream branches. NULL means
|
||||||
|
* the upstream branches are local to this repo.
|
||||||
|
*
|
||||||
|
* `remotes` is a list of refs that are upstream of local
|
||||||
|
*/
|
||||||
|
static int install_branch_config_multiple_remotes(int flag, const char *local,
|
||||||
|
const char *origin, struct string_list *remotes)
|
||||||
{
|
{
|
||||||
const char *shortname = NULL;
|
const char *shortname = NULL;
|
||||||
struct strbuf key = STRBUF_INIT;
|
struct strbuf key = STRBUF_INIT;
|
||||||
|
struct string_list_item *item;
|
||||||
int rebasing = should_setup_rebase(origin);
|
int rebasing = should_setup_rebase(origin);
|
||||||
|
|
||||||
if (skip_prefix(remote, "refs/heads/", &shortname)
|
if (!remotes->nr)
|
||||||
&& !strcmp(local, shortname)
|
BUG("must provide at least one remote for branch config");
|
||||||
&& !origin) {
|
if (rebasing && remotes->nr > 1)
|
||||||
warning(_("Not setting branch %s as its own upstream."),
|
die(_("cannot inherit upstream tracking configuration of "
|
||||||
local);
|
"multiple refs when rebasing is requested"));
|
||||||
return 0;
|
|
||||||
}
|
/*
|
||||||
|
* If the new branch is trying to track itself, something has gone
|
||||||
|
* wrong. Warn the user and don't proceed any further.
|
||||||
|
*/
|
||||||
|
if (!origin)
|
||||||
|
for_each_string_list_item(item, remotes)
|
||||||
|
if (skip_prefix(item->string, "refs/heads/", &shortname)
|
||||||
|
&& !strcmp(local, shortname)) {
|
||||||
|
warning(_("not setting branch '%s' as its own upstream."),
|
||||||
|
local);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
strbuf_addf(&key, "branch.%s.remote", local);
|
strbuf_addf(&key, "branch.%s.remote", local);
|
||||||
if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
|
if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
|
||||||
|
@ -75,8 +96,17 @@ int install_branch_config(int flag, const char *local, const char *origin, const
|
||||||
|
|
||||||
strbuf_reset(&key);
|
strbuf_reset(&key);
|
||||||
strbuf_addf(&key, "branch.%s.merge", local);
|
strbuf_addf(&key, "branch.%s.merge", local);
|
||||||
if (git_config_set_gently(key.buf, remote) < 0)
|
/*
|
||||||
|
* We want to overwrite any existing config with all the branches in
|
||||||
|
* "remotes". Override any existing config, then write our branches. If
|
||||||
|
* more than one is provided, use CONFIG_REGEX_NONE to preserve what
|
||||||
|
* we've written so far.
|
||||||
|
*/
|
||||||
|
if (git_config_set_gently(key.buf, NULL) < 0)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
for_each_string_list_item(item, remotes)
|
||||||
|
if (git_config_set_multivar_gently(key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0)
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
if (rebasing) {
|
if (rebasing) {
|
||||||
strbuf_reset(&key);
|
strbuf_reset(&key);
|
||||||
|
@ -87,29 +117,40 @@ int install_branch_config(int flag, const char *local, const char *origin, const
|
||||||
strbuf_release(&key);
|
strbuf_release(&key);
|
||||||
|
|
||||||
if (flag & BRANCH_CONFIG_VERBOSE) {
|
if (flag & BRANCH_CONFIG_VERBOSE) {
|
||||||
if (shortname) {
|
struct strbuf tmp_ref_name = STRBUF_INIT;
|
||||||
if (origin)
|
struct string_list friendly_ref_names = STRING_LIST_INIT_DUP;
|
||||||
printf_ln(rebasing ?
|
|
||||||
_("Branch '%s' set up to track remote branch '%s' from '%s' by rebasing.") :
|
for_each_string_list_item(item, remotes) {
|
||||||
_("Branch '%s' set up to track remote branch '%s' from '%s'."),
|
shortname = item->string;
|
||||||
local, shortname, origin);
|
skip_prefix(shortname, "refs/heads/", &shortname);
|
||||||
else
|
if (origin) {
|
||||||
printf_ln(rebasing ?
|
strbuf_addf(&tmp_ref_name, "%s/%s",
|
||||||
_("Branch '%s' set up to track local branch '%s' by rebasing.") :
|
origin, shortname);
|
||||||
_("Branch '%s' set up to track local branch '%s'."),
|
string_list_append_nodup(
|
||||||
local, shortname);
|
&friendly_ref_names,
|
||||||
} else {
|
strbuf_detach(&tmp_ref_name, NULL));
|
||||||
if (origin)
|
} else {
|
||||||
printf_ln(rebasing ?
|
string_list_append(
|
||||||
_("Branch '%s' set up to track remote ref '%s' by rebasing.") :
|
&friendly_ref_names, shortname);
|
||||||
_("Branch '%s' set up to track remote ref '%s'."),
|
}
|
||||||
local, remote);
|
|
||||||
else
|
|
||||||
printf_ln(rebasing ?
|
|
||||||
_("Branch '%s' set up to track local ref '%s' by rebasing.") :
|
|
||||||
_("Branch '%s' set up to track local ref '%s'."),
|
|
||||||
local, remote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remotes->nr == 1) {
|
||||||
|
/*
|
||||||
|
* Rebasing is only allowed in the case of a single
|
||||||
|
* upstream branch.
|
||||||
|
*/
|
||||||
|
printf_ln(rebasing ?
|
||||||
|
_("branch '%s' set up to track '%s' by rebasing.") :
|
||||||
|
_("branch '%s' set up to track '%s'."),
|
||||||
|
local, friendly_ref_names.items[0].string);
|
||||||
|
} else {
|
||||||
|
printf_ln(_("branch '%s' set up to track:"), local);
|
||||||
|
for_each_string_list_item(item, &friendly_ref_names)
|
||||||
|
printf_ln(" %s", item->string);
|
||||||
|
}
|
||||||
|
|
||||||
|
string_list_clear(&friendly_ref_names, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -118,14 +159,36 @@ out_err:
|
||||||
strbuf_release(&key);
|
strbuf_release(&key);
|
||||||
error(_("Unable to write upstream branch configuration"));
|
error(_("Unable to write upstream branch configuration"));
|
||||||
|
|
||||||
advise(_(tracking_advice),
|
advise(_("\nAfter fixing the error cause you may try to fix up\n"
|
||||||
origin ? origin : "",
|
"the remote tracking information by invoking:"));
|
||||||
origin ? "/" : "",
|
if (remotes->nr == 1)
|
||||||
shortname ? shortname : remote);
|
advise(" git branch --set-upstream-to=%s%s%s",
|
||||||
|
origin ? origin : "",
|
||||||
|
origin ? "/" : "",
|
||||||
|
remotes->items[0].string);
|
||||||
|
else {
|
||||||
|
advise(" git config --add branch.\"%s\".remote %s",
|
||||||
|
local, origin ? origin : ".");
|
||||||
|
for_each_string_list_item(item, remotes)
|
||||||
|
advise(" git config --add branch.\"%s\".merge %s",
|
||||||
|
local, item->string);
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int install_branch_config(int flag, const char *local, const char *origin,
|
||||||
|
const char *remote)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct string_list remotes = STRING_LIST_INIT_DUP;
|
||||||
|
|
||||||
|
string_list_append(&remotes, remote);
|
||||||
|
ret = install_branch_config_multiple_remotes(flag, local, origin, &remotes);
|
||||||
|
string_list_clear(&remotes, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is called when new_ref is branched off of orig_ref, and tries
|
* This is called when new_ref is branched off of orig_ref, and tries
|
||||||
* to infer the settings for branch.<new_ref>.{remote,merge} from the
|
* to infer the settings for branch.<new_ref>.{remote,merge} from the
|
||||||
|
|
|
@ -950,15 +950,15 @@ test_expect_success 'disabled option --set-upstream fails' '
|
||||||
test_must_fail git branch --set-upstream origin/main
|
test_must_fail git branch --set-upstream origin/main
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--set-upstream-to notices an error to set branch as own upstream' '
|
test_expect_success '--set-upstream-to notices an error to set branch as own upstream' "
|
||||||
git branch --set-upstream-to refs/heads/my13 my13 2>actual &&
|
git branch --set-upstream-to refs/heads/my13 my13 2>actual &&
|
||||||
cat >expect <<-\EOF &&
|
cat >expect <<-\EOF &&
|
||||||
warning: Not setting branch my13 as its own upstream.
|
warning: not setting branch 'my13' as its own upstream.
|
||||||
EOF
|
EOF
|
||||||
test_expect_code 1 git config branch.my13.remote &&
|
test_expect_code 1 git config branch.my13.remote &&
|
||||||
test_expect_code 1 git config branch.my13.merge &&
|
test_expect_code 1 git config branch.my13.merge &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
"
|
||||||
|
|
||||||
# Keep this test last, as it changes the current branch
|
# Keep this test last, as it changes the current branch
|
||||||
cat >expect <<EOF
|
cat >expect <<EOF
|
||||||
|
|
Загрузка…
Ссылка в новой задаче