Skip to content

Commit ba2452b

Browse files
committed
Merge branch 'tk/ambiguous-fetch-refspec'
Give hint when branch tracking cannot be established because fetch refspecs from multiple remote repositories overlap. * tk/ambiguous-fetch-refspec: tracking branches: add advice to ambiguous refspec error
2 parents 0f5e885 + e4921d8 commit ba2452b

File tree

5 files changed

+78
-9
lines changed

5 files changed

+78
-9
lines changed

Documentation/config/advice.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ advice.*::
44
can tell Git that you do not need help by setting these to 'false':
55
+
66
--
7+
ambiguousFetchRefspec::
8+
Advice shown when fetch refspec for multiple remotes map to
9+
the same remote-tracking branch namespace and causes branch
10+
tracking set-up to fail.
711
fetchShowForcedUpdates::
812
Advice shown when linkgit:git-fetch[1] takes a long time
913
to calculate forced updates after ref updates, or to warn

advice.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static struct {
3939
[ADVICE_ADD_EMPTY_PATHSPEC] = { "addEmptyPathspec", 1 },
4040
[ADVICE_ADD_IGNORED_FILE] = { "addIgnoredFile", 1 },
4141
[ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
42+
[ADVICE_AMBIGUOUS_FETCH_REFSPEC] = { "ambiguousFetchRefspec", 1 },
4243
[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
4344
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
4445
[ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },

advice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct string_list;
1717
ADVICE_ADD_EMPTY_PATHSPEC,
1818
ADVICE_ADD_IGNORED_FILE,
1919
ADVICE_AM_WORK_DIR,
20+
ADVICE_AMBIGUOUS_FETCH_REFSPEC,
2021
ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
2122
ADVICE_COMMIT_BEFORE_MERGE,
2223
ADVICE_DETACHED_HEAD,

branch.c

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,31 @@ struct tracking {
1818
int matches;
1919
};
2020

21+
struct find_tracked_branch_cb {
22+
struct tracking *tracking;
23+
struct string_list ambiguous_remotes;
24+
};
25+
2126
static int find_tracked_branch(struct remote *remote, void *priv)
2227
{
23-
struct tracking *tracking = priv;
28+
struct find_tracked_branch_cb *ftb = priv;
29+
struct tracking *tracking = ftb->tracking;
2430

2531
if (!remote_find_tracking(remote, &tracking->spec)) {
26-
if (++tracking->matches == 1) {
32+
switch (++tracking->matches) {
33+
case 1:
2734
string_list_append(tracking->srcs, tracking->spec.src);
2835
tracking->remote = remote->name;
29-
} else {
36+
break;
37+
case 2:
38+
/* there are at least two remotes; backfill the first one */
39+
string_list_append(&ftb->ambiguous_remotes, tracking->remote);
40+
/* fall through */
41+
default:
42+
string_list_append(&ftb->ambiguous_remotes, remote->name);
3043
free(tracking->spec.src);
3144
string_list_clear(tracking->srcs, 0);
45+
break;
3246
}
3347
tracking->spec.src = NULL;
3448
}
@@ -232,6 +246,10 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
232246
struct tracking tracking;
233247
struct string_list tracking_srcs = STRING_LIST_INIT_DUP;
234248
int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
249+
struct find_tracked_branch_cb ftb_cb = {
250+
.tracking = &tracking,
251+
.ambiguous_remotes = STRING_LIST_INIT_DUP,
252+
};
235253

236254
if (!track)
237255
BUG("asked to set up tracking, but tracking is disallowed");
@@ -240,7 +258,7 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
240258
tracking.spec.dst = (char *)orig_ref;
241259
tracking.srcs = &tracking_srcs;
242260
if (track != BRANCH_TRACK_INHERIT)
243-
for_each_remote(find_tracked_branch, &tracking);
261+
for_each_remote(find_tracked_branch, &ftb_cb);
244262
else if (inherit_tracking(&tracking, orig_ref))
245263
goto cleanup;
246264

@@ -255,9 +273,39 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
255273
goto cleanup;
256274
}
257275

258-
if (tracking.matches > 1)
259-
die(_("not tracking: ambiguous information for ref %s"),
260-
orig_ref);
276+
if (tracking.matches > 1) {
277+
int status = die_message(_("not tracking: ambiguous information for ref '%s'"),
278+
orig_ref);
279+
if (advice_enabled(ADVICE_AMBIGUOUS_FETCH_REFSPEC)) {
280+
struct strbuf remotes_advice = STRBUF_INIT;
281+
struct string_list_item *item;
282+
283+
for_each_string_list_item(item, &ftb_cb.ambiguous_remotes)
284+
/*
285+
* TRANSLATORS: This is a line listing a remote with duplicate
286+
* refspecs in the advice message below. For RTL languages you'll
287+
* probably want to swap the "%s" and leading " " space around.
288+
*/
289+
strbuf_addf(&remotes_advice, _(" %s\n"), item->string);
290+
291+
/*
292+
* TRANSLATORS: The second argument is a \n-delimited list of
293+
* duplicate refspecs, composed above.
294+
*/
295+
advise(_("There are multiple remotes whose fetch refspecs map to the remote\n"
296+
"tracking ref '%s':\n"
297+
"%s"
298+
"\n"
299+
"This is typically a configuration error.\n"
300+
"\n"
301+
"To support setting up tracking branches, ensure that\n"
302+
"different remotes' fetch refspecs map into different\n"
303+
"tracking namespaces."), orig_ref,
304+
remotes_advice.buf);
305+
strbuf_release(&remotes_advice);
306+
}
307+
exit(status);
308+
}
261309

262310
if (tracking.srcs->nr < 1)
263311
string_list_append(tracking.srcs, orig_ref);
@@ -267,6 +315,7 @@ static void setup_tracking(const char *new_ref, const char *orig_ref,
267315

268316
cleanup:
269317
string_list_clear(&tracking_srcs, 0);
318+
string_list_clear(&ftb_cb.ambiguous_remotes, 0);
270319
}
271320

272321
int read_branch_desc(struct strbuf *buf, const char *branch_name)

t/t3200-branch.sh

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,13 +1039,27 @@ test_expect_success 'checkout -b with -l makes reflog when core.logAllRefUpdates
10391039
git rev-parse --verify gamma@{0}
10401040
'
10411041

1042-
test_expect_success 'avoid ambiguous track' '
1042+
test_expect_success 'avoid ambiguous track and advise' '
10431043
git config branch.autosetupmerge true &&
10441044
git config remote.ambi1.url lalala &&
10451045
git config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&
10461046
git config remote.ambi2.url lilili &&
10471047
git config remote.ambi2.fetch refs/heads/lilili:refs/heads/main &&
1048-
test_must_fail git branch all1 main &&
1048+
cat <<-EOF >expected &&
1049+
fatal: not tracking: ambiguous information for ref '\''refs/heads/main'\''
1050+
hint: There are multiple remotes whose fetch refspecs map to the remote
1051+
hint: tracking ref '\''refs/heads/main'\'':
1052+
hint: ambi1
1053+
hint: ambi2
1054+
hint: ''
1055+
hint: This is typically a configuration error.
1056+
hint: ''
1057+
hint: To support setting up tracking branches, ensure that
1058+
hint: different remotes'\'' fetch refspecs map into different
1059+
hint: tracking namespaces.
1060+
EOF
1061+
test_must_fail git branch all1 main 2>actual &&
1062+
test_cmp expected actual &&
10491063
test -z "$(git config branch.all1.merge)"
10501064
'
10511065

0 commit comments

Comments
 (0)