Skip to content

Commit a3f40ec

Browse files
steadmongitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f443b22 commit a3f40ec

File tree

2 files changed

+106
-43
lines changed

2 files changed

+106
-43
lines changed

branch.c

Lines changed: 103 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,34 +49,64 @@ static int should_setup_rebase(const char *origin)
4949
return 0;
5050
}
5151

52-
static const char tracking_advice[] =
53-
N_("\n"
54-
"After fixing the error cause you may try to fix up\n"
55-
"the remote tracking information by invoking\n"
56-
"\"git branch --set-upstream-to=%s%s%s\".");
57-
58-
int install_branch_config(int flag, const char *local, const char *origin, const char *remote)
52+
/**
53+
* Install upstream tracking configuration for a branch; specifically, add
54+
* `branch.<name>.remote` and `branch.<name>.merge` entries.
55+
*
56+
* `flag` contains integer flags for options; currently only
57+
* BRANCH_CONFIG_VERBOSE is checked.
58+
*
59+
* `local` is the name of the branch whose configuration we're installing.
60+
*
61+
* `origin` is the name of the remote owning the upstream branches. NULL means
62+
* the upstream branches are local to this repo.
63+
*
64+
* `remotes` is a list of refs that are upstream of local
65+
*/
66+
static int install_branch_config_multiple_remotes(int flag, const char *local,
67+
const char *origin, struct string_list *remotes)
5968
{
6069
const char *shortname = NULL;
6170
struct strbuf key = STRBUF_INIT;
71+
struct string_list_item *item;
6272
int rebasing = should_setup_rebase(origin);
6373

64-
if (skip_prefix(remote, "refs/heads/", &shortname)
65-
&& !strcmp(local, shortname)
66-
&& !origin) {
67-
warning(_("Not setting branch %s as its own upstream."),
68-
local);
69-
return 0;
70-
}
74+
if (!remotes->nr)
75+
BUG("must provide at least one remote for branch config");
76+
if (rebasing && remotes->nr > 1)
77+
die(_("cannot inherit upstream tracking configuration of "
78+
"multiple refs when rebasing is requested"));
79+
80+
/*
81+
* If the new branch is trying to track itself, something has gone
82+
* wrong. Warn the user and don't proceed any further.
83+
*/
84+
if (!origin)
85+
for_each_string_list_item(item, remotes)
86+
if (skip_prefix(item->string, "refs/heads/", &shortname)
87+
&& !strcmp(local, shortname)) {
88+
warning(_("not setting branch '%s' as its own upstream."),
89+
local);
90+
return 0;
91+
}
7192

7293
strbuf_addf(&key, "branch.%s.remote", local);
7394
if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
7495
goto out_err;
7596

7697
strbuf_reset(&key);
7798
strbuf_addf(&key, "branch.%s.merge", local);
78-
if (git_config_set_gently(key.buf, remote) < 0)
99+
/*
100+
* We want to overwrite any existing config with all the branches in
101+
* "remotes". Override any existing config, then write our branches. If
102+
* more than one is provided, use CONFIG_REGEX_NONE to preserve what
103+
* we've written so far.
104+
*/
105+
if (git_config_set_gently(key.buf, NULL) < 0)
79106
goto out_err;
107+
for_each_string_list_item(item, remotes)
108+
if (git_config_set_multivar_gently(key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0)
109+
goto out_err;
80110

81111
if (rebasing) {
82112
strbuf_reset(&key);
@@ -87,29 +117,40 @@ int install_branch_config(int flag, const char *local, const char *origin, const
87117
strbuf_release(&key);
88118

89119
if (flag & BRANCH_CONFIG_VERBOSE) {
90-
if (shortname) {
91-
if (origin)
92-
printf_ln(rebasing ?
93-
_("Branch '%s' set up to track remote branch '%s' from '%s' by rebasing.") :
94-
_("Branch '%s' set up to track remote branch '%s' from '%s'."),
95-
local, shortname, origin);
96-
else
97-
printf_ln(rebasing ?
98-
_("Branch '%s' set up to track local branch '%s' by rebasing.") :
99-
_("Branch '%s' set up to track local branch '%s'."),
100-
local, shortname);
120+
struct strbuf tmp_ref_name = STRBUF_INIT;
121+
struct string_list friendly_ref_names = STRING_LIST_INIT_DUP;
122+
123+
for_each_string_list_item(item, remotes) {
124+
shortname = item->string;
125+
skip_prefix(shortname, "refs/heads/", &shortname);
126+
if (origin) {
127+
strbuf_addf(&tmp_ref_name, "%s/%s",
128+
origin, shortname);
129+
string_list_append_nodup(
130+
&friendly_ref_names,
131+
strbuf_detach(&tmp_ref_name, NULL));
132+
} else {
133+
string_list_append(
134+
&friendly_ref_names, shortname);
135+
}
136+
}
137+
138+
if (remotes->nr == 1) {
139+
/*
140+
* Rebasing is only allowed in the case of a single
141+
* upstream branch.
142+
*/
143+
printf_ln(rebasing ?
144+
_("branch '%s' set up to track '%s' by rebasing.") :
145+
_("branch '%s' set up to track '%s'."),
146+
local, friendly_ref_names.items[0].string);
101147
} else {
102-
if (origin)
103-
printf_ln(rebasing ?
104-
_("Branch '%s' set up to track remote ref '%s' by rebasing.") :
105-
_("Branch '%s' set up to track remote ref '%s'."),
106-
local, remote);
107-
else
108-
printf_ln(rebasing ?
109-
_("Branch '%s' set up to track local ref '%s' by rebasing.") :
110-
_("Branch '%s' set up to track local ref '%s'."),
111-
local, remote);
148+
printf_ln(_("branch '%s' set up to track:"), local);
149+
for_each_string_list_item(item, &friendly_ref_names)
150+
printf_ln(" %s", item->string);
112151
}
152+
153+
string_list_clear(&friendly_ref_names, 0);
113154
}
114155

115156
return 0;
@@ -118,14 +159,36 @@ int install_branch_config(int flag, const char *local, const char *origin, const
118159
strbuf_release(&key);
119160
error(_("Unable to write upstream branch configuration"));
120161

121-
advise(_(tracking_advice),
122-
origin ? origin : "",
123-
origin ? "/" : "",
124-
shortname ? shortname : remote);
162+
advise(_("\nAfter fixing the error cause you may try to fix up\n"
163+
"the remote tracking information by invoking:"));
164+
if (remotes->nr == 1)
165+
advise(" git branch --set-upstream-to=%s%s%s",
166+
origin ? origin : "",
167+
origin ? "/" : "",
168+
remotes->items[0].string);
169+
else {
170+
advise(" git config --add branch.\"%s\".remote %s",
171+
local, origin ? origin : ".");
172+
for_each_string_list_item(item, remotes)
173+
advise(" git config --add branch.\"%s\".merge %s",
174+
local, item->string);
175+
}
125176

126177
return -1;
127178
}
128179

180+
int install_branch_config(int flag, const char *local, const char *origin,
181+
const char *remote)
182+
{
183+
int ret;
184+
struct string_list remotes = STRING_LIST_INIT_DUP;
185+
186+
string_list_append(&remotes, remote);
187+
ret = install_branch_config_multiple_remotes(flag, local, origin, &remotes);
188+
string_list_clear(&remotes, 0);
189+
return ret;
190+
}
191+
129192
/*
130193
* This is called when new_ref is branched off of orig_ref, and tries
131194
* to infer the settings for branch.<new_ref>.{remote,merge} from the

t/t3200-branch.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,15 +950,15 @@ test_expect_success 'disabled option --set-upstream fails' '
950950
test_must_fail git branch --set-upstream origin/main
951951
'
952952

953-
test_expect_success '--set-upstream-to notices an error to set branch as own upstream' '
953+
test_expect_success '--set-upstream-to notices an error to set branch as own upstream' "
954954
git branch --set-upstream-to refs/heads/my13 my13 2>actual &&
955955
cat >expect <<-\EOF &&
956-
warning: Not setting branch my13 as its own upstream.
956+
warning: not setting branch 'my13' as its own upstream.
957957
EOF
958958
test_expect_code 1 git config branch.my13.remote &&
959959
test_expect_code 1 git config branch.my13.merge &&
960960
test_cmp expect actual
961-
'
961+
"
962962

963963
# Keep this test last, as it changes the current branch
964964
cat >expect <<EOF

0 commit comments

Comments
 (0)